Paid Memberships Pro - Version 1.8.6.2

Version Description

  • BUG: Stripe supports daily recurring subscriptions. Fixed issue where PMPro was still throwing a warning in some cases.
  • BUG: Removed warnings in the membership stats report.
  • CODE: Changed a couple instances of "since v2.0" to "since v1.8".
  • ENHANCEMENT: Added a hook for pmpro_checkout_order_free that functions like pmpro_checkout_order but fires for the blank order created for free checkouts.
  • ENHANCEMENT: Using site_url to get full URL to for the redirect_to value generated by !!referrer!! in the non-member/logged-out text strings in the advanced settings page. This fixes issues with using !!referrer!! on multisite setups. (Thanks, Keith Hall)
  • ENHANCEMENT: Updated pmpro_post_classes to work on the $post_id passed by the filter instead of the global $post variable.
  • ENHANCEMENT: Added pmpro_body_classes to add classes like pmpro-body-level-required, pmpro-body-level-1, and pmpro-body-has-access to the body tag based on the queried object.
  • ENHANCEMENT: Reformatted the PMPro Reports dashboard.
  • ENHANCEMENT: Now using separate invoice templates for email and print.
Download this release

Release Info

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

Code changes from version 1.8.5.6 to 1.8.6.2

Files changed (55) hide show
  1. adminpages/functions.php +1 -2
  2. adminpages/orders-print.php +39 -0
  3. adminpages/orders.php +149 -87
  4. adminpages/reports.php +65 -61
  5. adminpages/reports/login.php +32 -16
  6. adminpages/reports/memberships.php +624 -660
  7. adminpages/reports/sales.php +415 -406
  8. adminpages/templates/orders-email.php +71 -0
  9. adminpages/templates/orders-print.php +99 -0
  10. classes/class.pmproemail.php +51 -0
  11. classes/gateways/class.pmprogateway_payflowpro.php +42 -0
  12. classes/gateways/class.pmprogateway_stripe.php +8 -4
  13. css/admin.css +122 -118
  14. css/frontend.css +0 -3
  15. email/billable_invoice.html +6 -0
  16. includes/content.php +48 -4
  17. includes/currencies.php +11 -1
  18. includes/functions.php +2116 -2061
  19. includes/profile.php +2 -1
  20. includes/services.php +24 -0
  21. languages/email/vi_VN/admin_change.html +7 -0
  22. languages/email/vi_VN/admin_change_admin.html +5 -0
  23. languages/email/vi_VN/billing.html +16 -0
  24. languages/email/vi_VN/billing_admin.html +17 -0
  25. languages/email/vi_VN/billing_failure.html +11 -0
  26. languages/email/vi_VN/billing_failure_admin.html +11 -0
  27. languages/email/vi_VN/cancel.html +3 -0
  28. languages/email/vi_VN/cancel_admin.html +8 -0
  29. languages/email/vi_VN/checkout_check.html +17 -0
  30. languages/email/vi_VN/checkout_check_admin.html +17 -0
  31. languages/email/vi_VN/checkout_express.html +14 -0
  32. languages/email/vi_VN/checkout_express_admin.html +14 -0
  33. languages/email/vi_VN/checkout_free.html +8 -0
  34. languages/email/vi_VN/checkout_free_admin.html +8 -0
  35. languages/email/vi_VN/checkout_freetrial.html +19 -0
  36. languages/email/vi_VN/checkout_freetrial_admin.html +19 -0
  37. languages/email/vi_VN/checkout_paid.html +23 -0
  38. languages/email/vi_VN/checkout_paid_admin.html +23 -0
  39. languages/email/vi_VN/checkout_trial.html +23 -0
  40. languages/email/vi_VN/checkout_trial_admin.html +23 -0
  41. languages/email/vi_VN/credit_card_expiring.html +13 -0
  42. languages/email/vi_VN/default.html +1 -0
  43. languages/email/vi_VN/footer.html +4 -0
  44. languages/email/vi_VN/header.html +1 -0
  45. languages/email/vi_VN/invoice.html +19 -0
  46. languages/email/vi_VN/membership_expired.html +7 -0
  47. languages/email/vi_VN/membership_expiring.html +6 -0
  48. languages/email/vi_VN/trial_ending.html +8 -0
  49. languages/pmpro-vi_VN.mo +0 -0
  50. languages/pmpro-vi_VN.po +4556 -0
  51. pages/checkout.php +8 -4
  52. paid-memberships-pro.php +2 -2
  53. preheaders/checkout.php +756 -754
  54. readme.txt +33 -339
  55. services/stripe-webhook.php +32 -31
adminpages/functions.php CHANGED
@@ -55,8 +55,7 @@ function pmpro_checkLevelForStripeCompatibility($level = NULL)
55
  $level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . esc_sql($level) . "' LIMIT 1");
56
 
57
  //check this level
58
- if(($level->cycle_number > 0 && $level->cycle_period == "Day") ||
59
- $level->billing_limit > 0)
60
  {
61
  return false;
62
  }
55
  $level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . esc_sql($level) . "' LIMIT 1");
56
 
57
  //check this level
58
+ if($level->billing_limit > 0)
 
59
  {
60
  return false;
61
  }
adminpages/orders-print.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Order - Print View
4
+ *
5
+ * Gets the order and displays the print view template.
6
+ *
7
+ * @since 1.8.6
8
+ */
9
+
10
+ //only admins can get this
11
+ if ( ! function_exists( "current_user_can" ) || ( ! current_user_can( "manage_options" ) && ! current_user_can( "pmpro_ordersprint" ) ) ) {
12
+ die( __( "You do not have permissions to perform this action.", "pmpro" ) );
13
+ }
14
+
15
+ // Do we have an order ID?
16
+ if ( empty( $_REQUEST['order'] ) ) {
17
+ wp_redirect( admin_url( 'admin..php?page=pmpro-orders' ) );
18
+ exit;
19
+ }
20
+
21
+ // Get order and membership level.
22
+ $order = new MemberOrder($_REQUEST['order']);
23
+ $level = pmpro_getLevel($order->membership_id);
24
+
25
+ // Load template
26
+ if ( file_exists( get_stylesheet_directory() . '/paid-memberships-pro/pages/orders-print.php' ) ) {
27
+ $template = get_stylesheet_directory() . '/paid-memberships-pro/pages/orders-print.php';
28
+ } elseif ( file_exists( get_template_directory() . '/paid-memberships-pro/pages/orders-print.php' ) ) {
29
+ $template = get_template_directory() . '/paid-memberships-pro/pages/orders-print.php';
30
+ } else {
31
+ $template = PMPRO_DIR . '/adminpages/templates/orders-print.php';
32
+ }
33
+
34
+ require_once( $template );
35
+ ?>
36
+ <script>
37
+ window.print();
38
+ </script>
39
+
adminpages/orders.php CHANGED
@@ -57,6 +57,109 @@
57
  else
58
  $status = "";
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
61
  //deleting?
62
  if(!empty($_REQUEST['delete']))
@@ -81,8 +184,6 @@
81
 
82
  $thisyear = date("Y");
83
 
84
-
85
-
86
  //this array stores fields that should be read only
87
  $read_only_fields = apply_filters("pmpro_orders_read_only_fields", array("code", "payment_transaction_id", "subscription_transaction_id"));
88
 
@@ -564,7 +665,42 @@
564
  </form>
565
 
566
  <?php } else { ?>
567
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
568
  <form id="posts-filter" method="get" action="">
569
  <h2>
570
  <?php _e('Orders', 'pmpro');?>
@@ -646,8 +782,7 @@
646
 
647
  <?php
648
  //Note: only orders belonging to current levels can be filtered. There is no option for orders belonging to deleted levels
649
- $levels = pmpro_getAllLevels();
650
-
651
  ?>
652
  <select id="l" name="l">
653
  <?php foreach($levels as $level) { ?>
@@ -781,85 +916,6 @@
781
  </p>
782
 
783
  <?php
784
- //some vars for the search
785
- if(isset($_REQUEST['pn']))
786
- $pn = intval($_REQUEST['pn']);
787
- else
788
- $pn = 1;
789
-
790
- if(isset($_REQUEST['limit']))
791
- $limit = intval($_REQUEST['limit']);
792
- else
793
- {
794
- /**
795
- * Filter to set the default number of items to show per page
796
- * on the Orders page in the admin.
797
- *
798
- * @since 1.8.4.5
799
- *
800
- * @param int $limit The number of items to show per page.
801
- */
802
- $limit = apply_filters('pmpro_orders_per_page', 15);
803
- }
804
-
805
- $end = $pn * $limit;
806
- $start = $end - $limit;
807
-
808
- //filters
809
- if($filter == "all" || !$filter)
810
- $condition = "1=1";
811
- elseif($filter == "within-a-date-range")
812
- {
813
- $start_date = $start_year."-".$start_month."-".$start_day;
814
- $end_date = $end_year."-".$end_month."-".$end_day;
815
-
816
- //add times to dates
817
- $start_date = $start_date . " 00:00:00";
818
- $end_date = $end_date . " 23:59:59";
819
-
820
- $condition = "timestamp BETWEEN '".esc_sql($start_date)."' AND '".esc_sql($end_date)."'";
821
- }
822
- elseif($filter == "predefined-date-range")
823
- {
824
- if($predefined_date == "Last Month")
825
- {
826
- $start_date = date("Y-m-d", strtotime("first day of last month", current_time("timestamp")));
827
- $end_date = date("Y-m-d", strtotime("last day of last month", current_time("timestamp")));
828
- }
829
- elseif($predefined_date == "This Month")
830
- {
831
- $start_date = date("Y-m-d", strtotime("first day of this month", current_time("timestamp")));
832
- $end_date = date("Y-m-d", strtotime("last day of this month", current_time("timestamp")));
833
- }
834
- elseif($predefined_date == "This Year")
835
- {
836
- $year = date('Y');
837
- $start_date = date("Y-m-d", strtotime("first day of January $year", current_time("timestamp")));
838
- $end_date = date("Y-m-d", strtotime("last day of December $year", current_time("timestamp")));
839
- }
840
-
841
- elseif($predefined_date == "Last Year")
842
- {
843
- $year = date('Y') - 1;
844
- $start_date = date("Y-m-d", strtotime("first day of January $year", current_time("timestamp")));
845
- $end_date = date("Y-m-d", strtotime("last day of December $year", current_time("timestamp")));
846
- }
847
-
848
- //add times to dates
849
- $start_date = $start_date . " 00:00:00";
850
- $end_date = $end_date . " 23:59:59";
851
-
852
- $condition = "timestamp BETWEEN '".esc_sql($start_date)."' AND '".esc_sql($end_date)."'";
853
- }
854
- elseif($filter == "within-a-level")
855
- {
856
- $condition = "membership_id = " . esc_sql($l);
857
- }
858
- elseif($filter == "within-a-status")
859
- {
860
- $condition = "status = '" . esc_sql($status) . "' ";
861
- }
862
-
863
  //string search
864
  if($s)
865
  {
@@ -904,7 +960,7 @@
904
  <?php
905
  }
906
  ?>
907
- <table class="widefat">
908
  <thead>
909
  <tr class="thead">
910
  <th><?php _e('ID', 'pmpro');?></th>
@@ -921,6 +977,8 @@
921
  <th></th>
922
  <th></th>
923
  <th></th>
 
 
924
  </tr>
925
  </thead>
926
  <tbody id="orders" class="list:order orders-list">
@@ -997,6 +1055,12 @@
997
  <td align="center">
998
  <a href="javascript:askfirst('<?php echo str_replace("'", "\'", sprintf(__("Deleting orders is permanent and can affect active users. Are you sure you want to delete order %s?", "pmpro"), str_replace("'", "", $order->code)));?>', 'admin.php?page=pmpro-orders&delete=<?php echo $order->id;?>'); void(0);"><?php _e('delete', 'pmpro');?></a>
999
  </td>
 
 
 
 
 
 
1000
  </tr>
1001
  <?php
1002
  }
@@ -1013,7 +1077,6 @@
1013
  </tbody>
1014
  </table>
1015
  </form>
1016
-
1017
  <?php
1018
  //add normal args
1019
  $pagination_url = add_query_arg($url_params, get_admin_url(NULL, "/admin.php?page=pmpro-orders"));
@@ -1021,7 +1084,6 @@
1021
  ?>
1022
 
1023
  <?php } ?>
1024
-
1025
  <?php
1026
  require_once(dirname(__FILE__) . "/admin_footer.php");
1027
  ?>
57
  else
58
  $status = "";
59
 
60
+ //some vars for the search
61
+ if(isset($_REQUEST['pn']))
62
+ $pn = intval($_REQUEST['pn']);
63
+ else
64
+ $pn = 1;
65
+
66
+ if(isset($_REQUEST['limit']))
67
+ $limit = intval($_REQUEST['limit']);
68
+ else
69
+ {
70
+ /**
71
+ * Filter to set the default number of items to show per page
72
+ * on the Orders page in the admin.
73
+ *
74
+ * @since 1.8.4.5
75
+ *
76
+ * @param int $limit The number of items to show per page.
77
+ */
78
+ $limit = apply_filters('pmpro_orders_per_page', 15);
79
+ }
80
+
81
+ $end = $pn * $limit;
82
+ $start = $end - $limit;
83
+
84
+ //filters
85
+ if(empty($filter) || $filter === "all")
86
+ {
87
+ $condition = "1=1";
88
+ $filter = "all";
89
+ }
90
+ elseif($filter == "within-a-date-range")
91
+ {
92
+ $start_date = $start_year."-".$start_month."-".$start_day;
93
+ $end_date = $end_year."-".$end_month."-".$end_day;
94
+
95
+ //add times to dates
96
+ $start_date = $start_date . " 00:00:00";
97
+ $end_date = $end_date . " 23:59:59";
98
+
99
+ $condition = "timestamp BETWEEN '".esc_sql($start_date)."' AND '".esc_sql($end_date)."'";
100
+ }
101
+ elseif($filter == "predefined-date-range")
102
+ {
103
+ if($predefined_date == "Last Month")
104
+ {
105
+ $start_date = date("Y-m-d", strtotime("first day of last month", current_time("timestamp")));
106
+ $end_date = date("Y-m-d", strtotime("last day of last month", current_time("timestamp")));
107
+ }
108
+ elseif($predefined_date == "This Month")
109
+ {
110
+ $start_date = date("Y-m-d", strtotime("first day of this month", current_time("timestamp")));
111
+ $end_date = date("Y-m-d", strtotime("last day of this month", current_time("timestamp")));
112
+ }
113
+ elseif($predefined_date == "This Year")
114
+ {
115
+ $year = date('Y');
116
+ $start_date = date("Y-m-d", strtotime("first day of January $year", current_time("timestamp")));
117
+ $end_date = date("Y-m-d", strtotime("last day of December $year", current_time("timestamp")));
118
+ }
119
+
120
+ elseif($predefined_date == "Last Year")
121
+ {
122
+ $year = date('Y') - 1;
123
+ $start_date = date("Y-m-d", strtotime("first day of January $year", current_time("timestamp")));
124
+ $end_date = date("Y-m-d", strtotime("last day of December $year", current_time("timestamp")));
125
+ }
126
+
127
+ //add times to dates
128
+ $start_date = $start_date . " 00:00:00";
129
+ $end_date = $end_date . " 23:59:59";
130
+
131
+ $condition = "timestamp BETWEEN '".esc_sql($start_date)."' AND '".esc_sql($end_date)."'";
132
+ }
133
+ elseif($filter == "within-a-level")
134
+ {
135
+ $condition = "membership_id = " . esc_sql($l);
136
+ }
137
+ elseif($filter == "within-a-status")
138
+ {
139
+ $condition = "status = '" . esc_sql($status) . "' ";
140
+ }
141
+
142
+ //emailing?
143
+ if(!empty($_REQUEST['email']) && !empty($_REQUEST['order']))
144
+ {
145
+ $email = new PMProEmail();
146
+ $user = get_user_by('email', $_REQUEST['email']);
147
+ $order = new MemberOrder($_REQUEST['order']);
148
+ if($email->sendBillableInvoiceEmail($user, $order))
149
+ {
150
+ $pmpro_msg = __("Invoice emailed successfully.", "pmpro");
151
+ $pmpro_msgt = "success";
152
+ }
153
+ else
154
+ {
155
+ $pmpro_msg = __("Error emailing invoice.", "pmpro");
156
+ $pmpro_msgt = "error";
157
+ }
158
+
159
+ //clean up so we stay on the orders list view
160
+ unset($_REQUEST['order']);
161
+ $order = NULL;
162
+ }
163
 
164
  //deleting?
165
  if(!empty($_REQUEST['delete']))
184
 
185
  $thisyear = date("Y");
186
 
 
 
187
  //this array stores fields that should be read only
188
  $read_only_fields = apply_filters("pmpro_orders_read_only_fields", array("code", "payment_transaction_id", "subscription_transaction_id"));
189
 
665
  </form>
666
 
667
  <?php } else { ?>
668
+ <?php
669
+ /**
670
+ * Code to handle emailing billable invoices.
671
+ *
672
+ * @since 1.8.6
673
+ */
674
+ ?>
675
+ <script>
676
+ // Update fields in email modal.
677
+ jQuery(document).ready(function($) {
678
+ var order, order_id;
679
+ $('.email_link').click(function() {
680
+ order_id = $(this).data('order');
681
+ $('input[name=order]').val(order_id);
682
+ // Get email address from order ID
683
+ data = {
684
+ action: 'pmpro_get_order_json',
685
+ order_id: order_id
686
+ };
687
+ $.post(ajaxurl, data, function(response) {
688
+ order = JSON.parse(response);
689
+ $('input[name=email]').val(order.Email);
690
+ });
691
+ });
692
+ });
693
+ </script>
694
+ <?php add_thickbox(); ?>
695
+ <div id="email_invoice" style="display:none;">
696
+ <h3><?php _e('Email Invoice', 'pmpro'); ?></h3>
697
+ <form method="post" action="">
698
+ <input type="hidden" name="order" value="" />
699
+ <?php _e('Send an invoice for this order to: ', 'pmpro'); ?>
700
+ <input type="text" value="" name="email" />
701
+ <button class="button button-primary alignright"><?php _e('Send Email', 'pmpro'); ?></button>
702
+ </form>
703
+ </div>
704
  <form id="posts-filter" method="get" action="">
705
  <h2>
706
  <?php _e('Orders', 'pmpro');?>
782
 
783
  <?php
784
  //Note: only orders belonging to current levels can be filtered. There is no option for orders belonging to deleted levels
785
+ $levels = pmpro_getAllLevels(true, true);
 
786
  ?>
787
  <select id="l" name="l">
788
  <?php foreach($levels as $level) { ?>
916
  </p>
917
 
918
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
919
  //string search
920
  if($s)
921
  {
960
  <?php
961
  }
962
  ?>
963
+ <table class="widefat">
964
  <thead>
965
  <tr class="thead">
966
  <th><?php _e('ID', 'pmpro');?></th>
977
  <th></th>
978
  <th></th>
979
  <th></th>
980
+ <th></th>
981
+ <th></th>
982
  </tr>
983
  </thead>
984
  <tbody id="orders" class="list:order orders-list">
1055
  <td align="center">
1056
  <a href="javascript:askfirst('<?php echo str_replace("'", "\'", sprintf(__("Deleting orders is permanent and can affect active users. Are you sure you want to delete order %s?", "pmpro"), str_replace("'", "", $order->code)));?>', 'admin.php?page=pmpro-orders&delete=<?php echo $order->id;?>'); void(0);"><?php _e('delete', 'pmpro');?></a>
1057
  </td>
1058
+ <td align="center">
1059
+ <a href="admin-ajax.php?action=pmpro_orders_print_view&order=<?php echo $order->id; ?>" target="_blank"><?php _e('print', 'pmpro');?></a>
1060
+ </td>
1061
+ <td align="center">
1062
+ <a href="#TB_inline?width=600&height=200&inlineId=email_invoice" class="thickbox email_link" data-order="<?php echo $order->id; ?>"><?php _e('email', 'pmpro');?></a>
1063
+ </td>
1064
  </tr>
1065
  <?php
1066
  }
1077
  </tbody>
1078
  </table>
1079
  </form>
 
1080
  <?php
1081
  //add normal args
1082
  $pagination_url = add_query_arg($url_params, get_admin_url(NULL, "/admin.php?page=pmpro-orders"));
1084
  ?>
1085
 
1086
  <?php } ?>
 
1087
  <?php
1088
  require_once(dirname(__FILE__) . "/admin_footer.php");
1089
  ?>
adminpages/reports.php CHANGED
@@ -1,62 +1,66 @@
1
- <?php
2
- global $pmpro_reports;
3
-
4
- require_once(dirname(__FILE__) . "/admin_header.php");
5
-
6
- //default view, report widgets
7
- if(empty($_REQUEST['report']))
8
- {
9
- //wrapper
10
- ?>
11
- <div id="dashboard-widgets-wrap">
12
- <div id="dashboard-widgets" class="metabox-holder pmpro_reports-holder columns-2">
13
- <div id="postbox-container-1" class="postbox-container">
14
- <div id="normal-sortables" class="meta-box-sortables ui-sortable">
15
- <?php
16
-
17
- //report widgets
18
- $count = 0;
19
- $nreports = count($pmpro_reports);
20
- $split = false;
21
- foreach($pmpro_reports as $report => $title)
22
- {
23
- //make sure title is translated (since these are set before translations happen)
24
- $title = __($title, "pmpro");
25
-
26
- //put half of the report widgets in postbox-container-2
27
- if(!$split && $count++ > $nreports/2)
28
- {
29
- $split = true;
30
- ?>
31
- </div></div><div id="postbox-container-2" class="postbox-container"><div id="side-sortables" class="meta-box-sortables ui-sortable">
32
- <?php
33
- }
34
- ?>
35
- <div id="pmpro_report_<?php echo $report; ?>" class="postbox pmpro_clickable" onclick="location.href='<?php echo admin_url("admin.php?page=pmpro-reports&report=" . $report);?>';">
36
- <h3 class="hndle"><span><?php echo $title; ?></span></h3>
37
- <div class="inside">
38
- <?php call_user_func("pmpro_report_" . $report . "_widget"); ?>
39
- <div style="margin-top:10px;border-top: 1px solid #ddd; padding-top: 10px; text-align:center;">
40
- <a class="button button-primary" href="<?php echo admin_url("admin.php?page=pmpro-reports&report=" . $report);?>"><?php _e('Details', 'pmpro');?></a>
41
- </div>
42
- </div>
43
- </div>
44
- <?php
45
- }
46
-
47
- //end wrapper
48
- ?>
49
- </div>
50
- </div>
51
- </div>
52
- <?php
53
- }
54
- else
55
- {
56
- //view a single report
57
- $report = sanitize_text_field($_REQUEST['report']);
58
- call_user_func("pmpro_report_" . $report . "_page");
59
- }
60
-
61
- require_once(dirname(__FILE__) . "/admin_footer.php");
 
 
 
 
62
  ?>
1
+ <?php
2
+ global $pmpro_reports;
3
+
4
+ require_once(dirname(__FILE__) . "/admin_header.php");
5
+
6
+ //default view, report widgets
7
+ if(empty($_REQUEST['report']))
8
+ {
9
+ //wrapper
10
+ ?>
11
+ <div id="dashboard-widgets-wrap">
12
+ <div id="dashboard-widgets" class="metabox-holder pmpro_reports-holder">
13
+ <div id="postbox-container-1" class="postbox-container">
14
+ <div id="normal-sortables" class="meta-box-sortables ui-sortable">
15
+ <?php
16
+
17
+ //report widgets
18
+ $count = 0;
19
+ $nreports = count($pmpro_reports);
20
+ $split = false;
21
+ foreach($pmpro_reports as $report => $title)
22
+ {
23
+ //make sure title is translated (since these are set before translations happen)
24
+ $title = __($title, "pmpro");
25
+
26
+ //put half of the report widgets in postbox-container-2
27
+ if(!$split && $count++ > $nreports/2)
28
+ {
29
+ $split = true;
30
+ ?>
31
+ </div></div><div id="postbox-container-2" class="postbox-container"><div id="side-sortables" class="meta-box-sortables ui-sortable">
32
+ <?php
33
+ }
34
+ ?>
35
+ <div id="pmpro_report_<?php echo $report; ?>" class="postbox pmpro_clickable" onclick="location.href='<?php echo admin_url("admin.php?page=pmpro-reports&report=" . $report);?>';">
36
+ <h3 class="hndle"><span><?php echo $title; ?></span></h3>
37
+ <div class="inside">
38
+ <?php call_user_func("pmpro_report_" . $report . "_widget"); ?>
39
+ <p style="text-align:center;">
40
+ <a class="button button-primary" href="<?php echo admin_url("admin.php?page=pmpro-reports&report=" . $report);?>"><?php _e('Details', 'pmpro');?></a>
41
+ </p>
42
+ </div>
43
+ </div>
44
+ <?php
45
+ }
46
+
47
+ //end wrapper
48
+ ?>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ <?php
53
+ }
54
+ else
55
+ {
56
+ //view a single report
57
+ $report = sanitize_text_field($_REQUEST['report']);
58
+ call_user_func("pmpro_report_" . $report . "_page");
59
+ ?>
60
+ <hr />
61
+ <a class="button button-primary" href="<?php echo admin_url("admin.php?page=pmpro-reports");?>"><?php _e('Back to Reports Dashboard', 'pmpro');?></a>
62
+ <?php
63
+ }
64
+
65
+ require_once(dirname(__FILE__) . "/admin_footer.php");
66
  ?>
adminpages/reports/login.php CHANGED
@@ -23,22 +23,38 @@ function pmpro_report_login_widget()
23
  $views = get_option("pmpro_views", array("today"=>0, "thisday"=>date("Y-m-d", $now), "alltime"=>0, "month"=>0, "thismonth"=>date("n", $now)));
24
  $logins = get_option("pmpro_logins", array("today"=>0, "thisday"=>date("Y-m-d", $now), "alltime"=>0, "month"=>0, "thismonth"=>date("n", $now)));
25
  ?>
26
- <div style="width: 33%; float: left;">
27
- <p><?php _e('Visits Today', 'pmpro')?>: <?php echo $visits['today'];?></p>
28
- <p><?php _e('Visits This Month', 'pmpro')?>: <?php echo $visits['month'];?></p>
29
- <p><?php _e('Visits All Time', 'pmpro')?>: <?php echo $visits['alltime'];?></p>
30
- </div>
31
- <div style="width: 33%; float: left;">
32
- <p><?php _e('Views Today', 'pmpro')?>: <?php echo $views['today'];?></p>
33
- <p><?php _e('Views This Month', 'pmpro')?>: <?php echo $views['month'];?></p>
34
- <p><?php _e('Views All Time', 'pmpro')?>: <?php echo $views['alltime'];?></p>
35
- </div>
36
- <div style="width: 33%; float: left;">
37
- <p><?php _e('Logins Today', 'pmpro')?>: <?php echo $logins['today'];?></p>
38
- <p><?php _e('Logins This Month', 'pmpro')?>: <?php echo $logins['month'];?></p>
39
- <p><?php _e('Logins All Time', 'pmpro')?>: <?php echo $logins['alltime'];?></p>
40
- </div>
41
- <div class="clear"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  <?php
43
  }
44
 
23
  $views = get_option("pmpro_views", array("today"=>0, "thisday"=>date("Y-m-d", $now), "alltime"=>0, "month"=>0, "thismonth"=>date("n", $now)));
24
  $logins = get_option("pmpro_logins", array("today"=>0, "thisday"=>date("Y-m-d", $now), "alltime"=>0, "month"=>0, "thismonth"=>date("n", $now)));
25
  ?>
26
+ <span id="pmpro_report_login">
27
+ <table class="wp-list-table widefat fixed striped">
28
+ <thead>
29
+ <tr>
30
+ <th scope="col">&nbsp;</th>
31
+ <th scope="col"><?php _e('Visits','pmpro'); ?></th>
32
+ <th scope="col"><?php _e('Views','pmpro'); ?></th>
33
+ <th scope="col"><?php _e('Logins','pmpro'); ?></th>
34
+ </tr>
35
+ </thead>
36
+ <tbody>
37
+ <tr>
38
+ <th scope="row"><?php _e('Today','pmpro'); ?></th>
39
+ <td><?php echo number_format_i18n($visits['today']); ?></td>
40
+ <td><?php echo number_format_i18n($views['today']); ?></td>
41
+ <td><?php echo number_format_i18n($logins['today']);?></td>
42
+ </tr>
43
+ <tr>
44
+ <th scope="row"><?php _e('This Month','pmpro'); ?></th>
45
+ <td><?php echo number_format_i18n($visits['month']); ?></td>
46
+ <td><?php echo number_format_i18n($views['month']); ?></td>
47
+ <td><?php echo number_format_i18n($logins['month']); ?></td>
48
+ </tr>
49
+ <tr>
50
+ <th scope="row"><?php _e('All Time','pmpro'); ?></th>
51
+ <td><?php echo number_format_i18n($visits['alltime']); ?></td>
52
+ <td><?php echo number_format_i18n($views['alltime']);?></td>
53
+ <td><?php echo number_format_i18n($logins['alltime']); ?></td>
54
+ </tr>
55
+ </tbody>
56
+ </table>
57
+ </span>
58
  <?php
59
  }
60
 
adminpages/reports/memberships.php CHANGED
@@ -1,660 +1,624 @@
1
- <?php
2
- /*
3
- PMPro Report
4
- Title: Membership Stats
5
- Slug: memberships
6
-
7
- For each report, add a line like:
8
- global $pmpro_reports;
9
- $pmpro_reports['slug'] = 'Title';
10
-
11
- For each report, also write two functions:
12
- * pmpro_report_{slug}_widget() to show up on the report homepage.
13
- * pmpro_report_{slug}_page() to show up when users click on the report page widget.
14
- */
15
-
16
- global $pmpro_reports;
17
-
18
- $pmpro_reports['memberships'] = __('Membership Stats', 'pmpro');
19
-
20
- //queue Google Visualization JS on report page
21
- function pmpro_report_memberships_init() {
22
- if(is_admin() && isset($_REQUEST['report']) && $_REQUEST['report'] == "memberships" && isset($_REQUEST['page']) && $_REQUEST['page'] == "pmpro-reports")
23
- wp_enqueue_script("jsapi", "https://www.google.com/jsapi");
24
- }
25
- add_action( 'init', 'pmpro_report_memberships_init' );
26
-
27
-
28
- //widget
29
- function pmpro_report_memberships_widget() {
30
- global $wpdb, $pmpro_currency_symbol;
31
- ?>
32
- <style type="text/css">
33
- #pmpro_report_memberships .section-label {
34
- margin: 15px 0;
35
- font-size: 18px;
36
- text-align: left;
37
- display: block;
38
- }
39
-
40
- #pmpro_report_memberships .section-label:first-child {
41
- margin-top: 0;
42
- }
43
-
44
- #pmpro_report_memberships div {text-align: center;}
45
- #pmpro_report_memberships em {display: block; font-style: normal; font-size: 2em; margin: 5px; line-height: 26px;}
46
- </style>
47
- <span id="pmpro_report_memberships">
48
- <label class="section-label"><?php _e('Signups', 'pmpro');?>:</label>
49
- <div style="width: 25%; float: left;">
50
- <label><?php _e('All Time', 'pmpro');?></label>
51
- <em><?php echo pmpro_getSignups( 'all time' ); ?></em>
52
- </div>
53
- <div style="width: 25%; float: left;">
54
- <label><?php _e('This Year', 'pmpro');?></label>
55
- <em><?php echo pmpro_getSignups( 'this year' ); ?></em>
56
- </div>
57
- <div style="width: 25%; float: left;">
58
- <label><?php _e('This Month', 'pmpro');?></label>
59
- <em><?php echo pmpro_getSignups( 'this month' ); ?></em>
60
- </div>
61
- <div style="width: 25%; float: left;">
62
- <label><?php _e('Today', 'pmpro');?></label>
63
- <em><?php echo pmpro_getSignups( 'today' ); ?></em>
64
- </div>
65
- <div class="clear"></div>
66
-
67
- <label class="section-label"><?php _e('Cancellations', 'pmpro');?>:</label>
68
- <div style="width: 25%; float: left;">
69
- <label><?php _e('All Time', 'pmpro');?></label>
70
- <em><?php echo pmpro_getCancellations( 'all time' ); ?></em>
71
- </div>
72
- <div style="width: 25%; float: left;">
73
- <label><?php _e('This Year', 'pmpro');?></label>
74
- <em><?php echo pmpro_getCancellations( 'this year' ); ?></em>
75
- </div>
76
- <div style="width: 25%; float: left;">
77
- <label><?php _e('This Month', 'pmpro');?></label>
78
- <em><?php echo pmpro_getCancellations( 'this month' ); ?></em>
79
- </div>
80
- <div style="width: 25%; float: left;">
81
- <label><?php _e('Today', 'pmpro');?></label>
82
- <em><?php echo pmpro_getCancellations( 'today' ); ?></em>
83
- </div>
84
- <div class="clear"></div>
85
-
86
- <label class="section-label"><?php _e('Other Stats', 'pmpro');?>:</label>
87
- <div style="width: 33%; float: left;">
88
- <label><?php _e('Monthly Recurring Revenue (MRR)', 'pmpro');?></label>
89
- <em><?php echo pmpro_formatPrice(pmpro_getMRR( 'all time' )); ?></em>
90
- </div>
91
- <div style="width: 33%; float: left;">
92
- <label><?php _e('Cancellation Rate', 'pmpro');?></label>
93
- <em><?php echo pmpro_getCancellationRate('all time' ); ?>%</em>
94
- </div>
95
- <div style="width: 33%; float: left;">
96
- <label><?php _e('Lifetime Value (LTV)', 'pmpro');?></label>
97
- <em><?php echo pmpro_formatPrice(pmpro_getLTV('all time')); ?></em>
98
- </div>
99
- <div class="clear"></div>
100
- </span>
101
- <?php
102
- }
103
-
104
- function pmpro_report_memberships_page()
105
- {
106
- global $wpdb, $pmpro_currency_symbol;
107
-
108
- //get values from form
109
- if(isset($_REQUEST['type']))
110
- $type = sanitize_text_field($_REQUEST['type']);
111
- else
112
- $type = "signup_v_cancel";
113
-
114
- if(isset($_REQUEST['period']))
115
- $period = sanitize_text_field($_REQUEST['period']);
116
- else
117
- $period = "monthly";
118
-
119
- if(isset($_REQUEST['month']))
120
- $month = intval($_REQUEST['month']);
121
- else
122
- $month = date("n");
123
-
124
- $thisyear = date("Y");
125
- if(isset($_REQUEST['year']))
126
- $year = intval($_REQUEST['year']);
127
- else
128
- $year = date("Y");
129
-
130
- if(isset($_REQUEST['level']))
131
- $l = intval($_REQUEST['level']);
132
- else
133
- $l = "";
134
-
135
- //calculate start date and how to group dates returned from DB
136
- if($period == "daily")
137
- {
138
- $startdate = $year . '-' . substr("0" . $month, strlen($month) - 1, 2) . '-01';
139
- $enddate = $year . '-' . substr("0" . $month, strlen($month) - 1, 2) . '-32';
140
- $date_function = 'DAY';
141
- }
142
- elseif($period == "monthly")
143
- {
144
- $startdate = $year . '-01-01';
145
- $enddate = strval(intval($year)+1) . '-01-01';
146
- $date_function = 'MONTH';
147
- }
148
- elseif($period == "annual")
149
- {
150
- $startdate = '1960-01-01'; //all time
151
- $date_function = 'YEAR';
152
- }
153
-
154
- //testing or live data
155
- $gateway_environment = pmpro_getOption("gateway_environment");
156
-
157
- //get data
158
- if ( $type === "signup_v_cancel" ) {
159
- $sqlQuery = "SELECT $date_function(startdate) as date, COUNT(DISTINCT user_id) as signups
160
- FROM $wpdb->pmpro_memberships_users WHERE startdate >= '" . $startdate . "' ";
161
-
162
- if(!empty($enddate))
163
- $sqlQuery .= "AND startdate < '" . $enddate . "' ";
164
- }
165
- if ( $type === "mrr_ltv" ) {
166
- // Get total revenue, number of months in system, and date
167
- if ( $period == 'annual' )
168
- $sqlQuery = "SELECT SUM(total) as total, COUNT(DISTINCT MONTH(timestamp)) as months, $date_function(timestamp) as date
169
- FROM $wpdb->pmpro_membership_orders WHERE status NOT IN('refunded', 'review', 'token')
170
- AND timestamp >= '" . $startdate . "' AND gateway_environment = '" . esc_sql($gateway_environment) . "' ";
171
-
172
- if ( $period == 'monthly' )
173
- $sqlQuery = "SELECT SUM(total) as total, $date_function(timestamp) as date
174
- FROM $wpdb->pmpro_membership_orders WHERE status NOT IN('refunded', 'review', 'token')
175
- AND timestamp >= '" . $startdate . "' AND gateway_environment = '" . esc_sql($gateway_environment) . "' ";
176
-
177
- if(!empty($enddate))
178
- $sqlQuery .= "AND timestamp < '" . $enddate . "' ";
179
- }
180
-
181
- if(!empty($l))
182
- $sqlQuery .= "AND membership_id IN(" . $l . ") ";
183
-
184
- $sqlQuery .= " GROUP BY date ORDER BY date ";
185
-
186
- $dates = $wpdb->get_results($sqlQuery);
187
-
188
- //fill in blanks in dates
189
- $cols = array();
190
- if($period == "daily")
191
- {
192
- $lastday = date("t", strtotime($startdate, current_time("timestamp")));
193
-
194
- for($i = 1; $i <= $lastday; $i++)
195
- {
196
- // Signups vs. Cancellations
197
- if ( $type === "signup_v_cancel" ) {
198
- $cols[$i] = new stdClass();
199
- $cols[$i]->signups = 0;
200
- foreach($dates as $date)
201
- {
202
- if( $date->date == $i ) {
203
- $cols[$i]->signups = $date->signups;
204
- }
205
- }
206
- }
207
- }
208
- }
209
- elseif($period == "monthly")
210
- {
211
- for($i = 1; $i < 13; $i++)
212
- {
213
- // Signups vs. Cancellations
214
- if ( $type === "signup_v_cancel" ) {
215
- $cols[$i] = new stdClass();
216
- $cols[$i]->date = $i;
217
- $cols[$i]->signups = 0;
218
- foreach($dates as $date)
219
- {
220
- if( $date->date == $i ) {
221
- $cols[$i]->date = $date->date;
222
- $cols[$i]->signups = $date->signups;
223
- }
224
- }
225
- }
226
-
227
- // MRR & LTV
228
- if ( $type === "mrr_ltv" ) {
229
- $cols[$i] = new stdClass();
230
- $cols[$i]->date = $i;
231
- $cols[$i]->months = 1;
232
- foreach($dates as $date)
233
- {
234
- if( $date->date == $i ) {
235
- $cols[$i]->total = $date->total;
236
- }
237
- }
238
- }
239
- }
240
- }
241
- elseif($period == "annual") //annual
242
- {
243
- }
244
-
245
- $dates = ( ! empty( $cols ) ) ? $cols : $dates;
246
-
247
- // Signups vs. cancellations
248
- if ( $type === "signup_v_cancel" )
249
- {
250
- $sqlQuery = "SELECT $date_function(mu1.modified) as date, COUNT(DISTINCT mu1.user_id) as cancellations
251
- FROM $wpdb->pmpro_memberships_users mu1
252
- LEFT JOIN $wpdb->pmpro_memberships_users mu2 ON mu1.user_id = mu2.user_id AND
253
- mu2.modified > mu1.enddate AND
254
- DATE_ADD(mu1.modified, INTERVAL 1 DAY) > mu2.startdate
255
- WHERE mu1.status = 'inactive'
256
- AND mu2.id IS NULL
257
- AND mu1.startdate >= '" . $startdate . "'
258
- AND mu1.startdate < '" . $enddate . "' ";
259
-
260
- //restrict by level
261
- if(!empty($l))
262
- $sqlQuery .= "AND membership_id IN(" . $l . ") ";
263
-
264
- $sqlQuery .= " GROUP BY date ORDER BY date ";
265
-
266
- $cdates = $wpdb->get_results($sqlQuery, OBJECT_K);
267
-
268
- foreach( $dates as &$date )
269
- {
270
- if(!empty($cdates[$date->date]))
271
- $date->cancellations = $cdates[$date->date]->cancellations;
272
- else
273
- $date->cancellations = 0;
274
- }
275
- }
276
-
277
- // MRR & LTV
278
- if ( $type === "mrr_ltv" && count( $dates ) === 1 ) {
279
- $dummy_date = new stdClass();
280
- $dummy_date->total = 0;
281
- $dummy_date->months = 0;
282
- $dummy_date->date = $dates[0]->date - 1;
283
- array_unshift( $dates, $dummy_date ); // Add to beginning
284
- }
285
- ?>
286
- <form id="posts-filter" method="get" action="">
287
- <h2>
288
- <?php _e('Membership Stats', 'pmpro');?>
289
- </h2>
290
- <ul class="subsubsub">
291
- <li>
292
- <?php _ex('Show', 'Dropdown label, e.g. Show Daily Revenue for January', 'pmpro')?>
293
- <select id="period" name="period">
294
- <option value="daily" <?php selected($period, "daily");?>><?php _e('Daily', 'pmpro');?></option>
295
- <option value="monthly" <?php selected($period, "monthly");?>><?php _e('Monthly', 'pmpro');?></option>
296
- <option value="annual" <?php selected($period, "annual");?>><?php _e('Annual', 'pmpro');?></option>
297
- </select>
298
- <select id="type" name="type">
299
- <option value="signup_v_cancel" <?php selected($type, "signup_v_cancel");?>><?php _e('Signups vs. Cancellations', 'pmpro');?></option>
300
- <?php /*
301
- <option value="mrr_ltv" <?php selected($type, "mrr_ltv");?>><?php _e('MRR & LTV', 'pmpro');?></option>
302
- */ ?>
303
- </select>
304
- <span id="for"><?php _ex('for', 'Dropdown label, e.g. Show Daily Revenue for January', 'pmpro')?></span>
305
- <select id="month" name="month">
306
- <?php for($i = 1; $i < 13; $i++) { ?>
307
- <option value="<?php echo $i;?>" <?php selected($month, $i);?>><?php echo date("F", mktime(0, 0, 0, $i, 2));?></option>
308
- <?php } ?>
309
- </select>
310
- <select id="year" name="year">
311
- <?php for($i = $thisyear; $i > 2007; $i--) { ?>
312
- <option value="<?php echo $i;?>" <?php selected($year, $i);?>><?php echo $i;?></option>
313
- <?php } ?>
314
- </select>
315
- <span id="for"><?php _ex('for', 'Dropdown label, e.g. Show Daily Revenue for January', 'pmpro')?></span>
316
- <select name="level">
317
- <option value="" <?php if(!$l) { ?>selected="selected"<?php } ?>><?php _e('All Levels', 'pmpro');?></option>
318
- <?php
319
- $levels = $wpdb->get_results("SELECT id, name FROM $wpdb->pmpro_membership_levels ORDER BY name");
320
- foreach($levels as $level)
321
- {
322
- ?>
323
- <option value="<?php echo $level->id?>" <?php if($l == $level->id) { ?>selected="selected"<?php } ?>><?php echo $level->name?></option>
324
- <?php
325
- }
326
- ?>
327
- </select>
328
-
329
- <input type="hidden" name="page" value="pmpro-reports" />
330
- <input type="hidden" name="report" value="memberships" />
331
- <input type="submit" value="<?php _ex('Generate Report', 'Submit button value.', 'pmpro');?>" />
332
- </li>
333
- </ul>
334
-
335
- <div id="chart_div" style="clear: both; width: 100%; height: 500px;"></div>
336
-
337
- <script>
338
- //update month/year when period dropdown is changed
339
- jQuery(document).ready(function() {
340
- jQuery('#period').change(function() {
341
- pmpro_ShowMonthOrYear();
342
- });
343
- });
344
-
345
- function pmpro_ShowMonthOrYear()
346
- {
347
- var period = jQuery('#period').val();
348
- if(period == 'daily')
349
- {
350
- jQuery('#for').show();
351
- jQuery('#month').show();
352
- jQuery('#year').show();
353
- }
354
- else if(period == 'monthly')
355
- {
356
- jQuery('#for').show();
357
- jQuery('#month').hide();
358
- jQuery('#year').show();
359
- }
360
- else
361
- {
362
- jQuery('#for').hide();
363
- jQuery('#month').hide();
364
- jQuery('#year').hide();
365
- }
366
- }
367
-
368
- pmpro_ShowMonthOrYear();
369
-
370
- //draw the chart
371
- google.load("visualization", "1", {packages:["corechart"]});
372
- google.setOnLoadCallback(drawChart);
373
- function drawChart() {
374
-
375
- var data = google.visualization.arrayToDataTable([
376
- <?php if ( $type === "signup_v_cancel" ) : // Signups vs. cancellations ?>
377
- ['<?php echo $date_function;?>', 'Signups', 'Cancellations'],
378
- <?php foreach($dates as $key => $value) { ?>
379
- ['<?php if($period == "monthly") echo date("M", mktime(0,0,0,$value->date,2)); else if($period == "daily") echo $key; else echo $value->date;?>', <?php echo $value->signups; ?>, <?php echo $value->cancellations; ?>],
380
- <?php } ?>
381
- <?php endif; ?>
382
-
383
- <?php if ( $type === "mrr_ltv" ) : // Signups vs. cancellations ?>
384
- ['<?php echo $date_function;?>', 'MRR', 'LTV'],
385
- <?php foreach($dates as $key => $value) { ?>
386
- ['<?php if($period == "monthly") echo date("M", mktime(0,0,0,$value->date,2)); else if($period == "daily") echo $key; else echo $value->date;?>', <?php echo (($mrr = $value->total / $value->months) && $mrr != 0) ? $mrr : 0; ?>, <?php echo pmpro_getLTV($period, NULL, $mrr ); ?>],
387
- <?php } ?>
388
- <?php endif; ?>
389
- ]);
390
-
391
- var options = {
392
- colors: ['#0099c6', '#dc3912'],
393
- hAxis: {title: '<?php echo $date_function;?>', titleTextStyle: {color: 'black'}, maxAlternation: 1},
394
- vAxis: {color: 'green', titleTextStyle: {color: '#51a351'}},
395
- };
396
-
397
- <?php if ( $type === "signup_v_cancel" ) : // Signups vs. cancellations ?>
398
- var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
399
- <?php elseif ( $type === "mrr_ltv" ) : // MRR & LTV ?>
400
-
401
- <?php
402
- //prefix or suffix?
403
- if(pmpro_getCurrencyPosition() == "right")
404
- $position = "suffix";
405
- else
406
- $position = "prefix";
407
- ?>
408
-
409
- var formatter = new google.visualization.NumberFormat({<?php echo $position;?>: '<?php echo html_entity_decode($pmpro_currency_symbol);?>'});
410
- formatter.format(data, 2);
411
- var formatter = new google.visualization.NumberFormat({<?php echo $position;?>: '<?php echo html_entity_decode($pmpro_currency_symbol);?>'});
412
- formatter.format(data, 1);
413
-
414
- var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
415
- <?php endif; ?>
416
- chart.draw(data, options);
417
- }
418
- </script>
419
-
420
- </form>
421
- <?php
422
- }
423
-
424
-
425
-
426
- /*
427
- Other code required for your reports. This file is loaded every time WP loads with PMPro enabled.
428
- */
429
-
430
- //get signups
431
- function pmpro_getSignups($period = false, $levels = 'all')
432
- {
433
- //check for a transient
434
- $cache = get_transient( 'pmpro_report_memberships_signups' );
435
- if( ! empty( $cache ) && ! empty( $cache[$period] ) && ! empty( $cache[$period][$levels] ) )
436
- return $cache[$period][$levels];
437
-
438
- //a sale is an order with status = success
439
- if( $period == 'today' )
440
- $startdate = date(' Y-m-d' );
441
- elseif( $period == 'this month')
442
- $startdate = date( 'Y-m' ) . '-01';
443
- elseif( $period == 'this year')
444
- $startdate = date( 'Y' ) . '-01-01';
445
- else
446
- $startdate = '';
447
-
448
-
449
- //build query
450
- global $wpdb;
451
-
452
- $sqlQuery = "SELECT COUNT(DISTINCT user_id) FROM $wpdb->pmpro_memberships_users WHERE startdate >= '" . $startdate . "' ";
453
-
454
- //restrict by level
455
- if(!empty($levels) && $levels != 'all')
456
- $sqlQuery .= "AND membership_id IN(" . $levels . ") ";
457
-
458
- $signups = $wpdb->get_var($sqlQuery);
459
-
460
- //save in cache
461
- if(!empty($cache) && !empty($cache[$period]))
462
- $cache[$period][$levels] = $signups;
463
- elseif(!empty($cache))
464
- $cache[$period] = array($levels => $signups);
465
- else
466
- $cache = array($period => array($levels => $signups));
467
-
468
- set_transient("pmpro_report_memberships_signups", $cache, 3600*24);
469
-
470
- return $signups;
471
- }
472
-
473
- //get cancellations
474
- function pmpro_getCancellations($period = false, $levels = 'all')
475
- {
476
- //check for a transient
477
- $cache = get_transient( 'pmpro_report_memberships_cancellations' );
478
- if( ! empty( $cache ) && ! empty( $cache[$period] ) && ! empty( $cache[$period][$levels] ) )
479
- return $cache[$period][$levels];
480
-
481
- //figure out start date
482
- if( $period == 'today' )
483
- $startdate = date(' Y-m-d' );
484
- elseif( $period == 'this month')
485
- $startdate = date( 'Y-m' ) . '-01';
486
- elseif( $period == 'this year')
487
- $startdate = date( 'Y' ) . '-01-01';
488
- else
489
- $startdate = '';
490
-
491
- $startdate_plus_one = strtotime( $startdate . + ' + 1 day', current_time("timestamp") );
492
-
493
- /*
494
- build query.
495
- cancellations are marked in the memberships users table with status = 'inactive'
496
- we try to ignore cancellations when the user gets a new level with 24 hours (probably an upgrade or downgrade)
497
- */
498
- global $wpdb;
499
-
500
- //$sqlQuery = "SELECT mu1.user_id, mu2.user_id FROM $wpdb->pmpro_memberships_users mu1 LEFT JOIN $wpdb->pmpro_memberships_users mu2 ON mu1.user_id = mu2.user_id AND mu2.status = 'inactive' AND mu2.startdate > mu1.startdate";
501
- $sqlQuery = "SELECT COUNT(mu1.id)
502
- FROM $wpdb->pmpro_memberships_users mu1
503
- LEFT JOIN $wpdb->pmpro_memberships_users mu2 ON mu1.user_id = mu2.user_id AND
504
- mu2.modified > mu1.enddate AND
505
- DATE_ADD(mu1.modified, INTERVAL 1 DAY) > mu2.startdate
506
- WHERE mu1.status = 'inactive'
507
- AND mu2.id IS NULL
508
- AND mu1.startdate >= '" . $startdate . "' ";
509
-
510
- //restrict by level
511
- if(!empty($levels) && $levels != 'all')
512
- $sqlQuery .= "AND membership_id IN(" . $levels . ") ";
513
-
514
- $cancellations = $wpdb->get_var($sqlQuery);
515
-
516
- //save in cache
517
- if(!empty($cache) && !empty($cache[$period]) && is_array($cache[$period]))
518
- $cache[$period][$levels] = $cancellations;
519
- elseif(!empty($cache))
520
- $cache[$period] = array($levels => $cancellations);
521
- else
522
- $cache = array($period => array($levels => $cancellations));
523
-
524
- set_transient("pmpro_report_memberships_cancellations", $cache, 3600*24);
525
-
526
- return $cancellations;
527
- }
528
-
529
- //get MRR
530
- function pmpro_getMRR($period, $levels = 'all')
531
- {
532
- //check for a transient
533
- //$cache = get_transient("pmpro_report_mrr");
534
- if(!empty($cache) && !empty($cache[$period]) && !empty($cache[$period][$levels]))
535
- return $cache[$period][$levels];
536
-
537
- //a sale is an order with status NOT IN refunded, review, token, error
538
- if($period == "this month")
539
- $startdate = date("Y-m") . "-01";
540
- elseif($period == "this year")
541
- $startdate = date("Y") . "-01-01";
542
- else
543
- $startdate = "";
544
-
545
- $gateway_environment = pmpro_getOption("gateway_environment");
546
-
547
- //build query
548
- global $wpdb;
549
- // Get total revenue
550
- $sqlQuery = "SELECT SUM(total) FROM $wpdb->pmpro_membership_orders WHERE status NOT IN('refunded', 'review', 'token', 'error') AND timestamp >= '" . $startdate . "' AND gateway_environment = '" . esc_sql($gateway_environment) . "' ";
551
-
552
- //restrict by level
553
- if(!empty($levels) && $levels != 'all') {
554
- $sqlQuery .= "AND membership_id IN(" . $levels . ") ";
555
- }
556
-
557
- $revenue = $wpdb->get_var($sqlQuery);
558
-
559
- //when was the first order
560
- $first_order_timestamp = $wpdb->get_var("SELECT UNIX_TIMESTAMP(`timestamp`) FROM $wpdb->pmpro_membership_orders WHERE `timestamp` IS NOT NULL AND `timestamp` > '0000-00-00 00:00:00' ORDER BY `timestamp` LIMIT 1");
561
-
562
- //if we don't have a timestamp, we can't do this
563
- if(empty($first_order_timestamp))
564
- return false;
565
-
566
- //how many months ago was the first order
567
- $months = $wpdb->get_var("SELECT PERIOD_DIFF('" . date("Ym") . "', '" . date("Ym", $first_order_timestamp) . "')");
568
-
569
- /* this works in PHP 5.3+ without using MySQL to get the diff
570
- $date1 = new DateTime(date("Y-m-d", $first_order_timestamp));
571
- $date2 = new DateTime(date("Y-m-d"));
572
- $interval = $date1->diff($date2);
573
- $years = intval($interval->format('%y'));
574
- $months = $years*12 + intval($interval->format('%m'));
575
- */
576
-
577
- if($months > 0)
578
- $mrr = $revenue / $months;
579
- else
580
- $mrr = 0;
581
-
582
- //save in cache
583
- if(!empty($cache) && !empty($cache[$period]))
584
- $cache[$period][$levels] = $mrr;
585
- elseif(!empty($cache))
586
- $cache[$period] = array($levels => $mrr);
587
- else
588
- $cache = array($period => array($levels => $mrr));
589
-
590
- set_transient("pmpro_report_mrr", $cache, 3600*24);
591
-
592
- return $mrr;
593
- }
594
-
595
- //get Cancellation Rate
596
- function pmpro_getCancellationRate($period, $levels = 'all')
597
- {
598
- //check for a transient
599
- $cache = get_transient("pmpro_report_cancellation_rate");
600
- if(!empty($cache) && !empty($cache[$period]) && !empty($cache[$period][$levels]))
601
- return $cache[$period][$levels];
602
-
603
- $signups = pmpro_getSignups($period, $levels);
604
- $cancellations = pmpro_getCancellations($period, $levels);
605
-
606
- if(empty($signups))
607
- return false;
608
-
609
- $rate = number_format(($cancellations / $signups)*100, 2);
610
-
611
- //save in cache
612
- if(!empty($cache) && !empty($cache[$period]))
613
- $cache[$period][$levels] = $rate;
614
- elseif(!empty($cache))
615
- $cache[$period] = array($levels => $rate);
616
- else
617
- $cache = array($period => array($levels => $rate));
618
-
619
- set_transient("pmpro_report_cancellation_rate", $cache, 3600*24);
620
-
621
- return $rate;
622
- }
623
-
624
- //get LTV
625
- function pmpro_getLTV($period, $levels = 'all', $mrr = NULL, $signups = NULL, $cancellation_rate = NULL)
626
- {
627
- if(empty($mrr))
628
- $mrr = pmpro_getMRR($period, $levels);
629
- if(empty($signups))
630
- $signups = pmpro_getSignups($period, $levels);
631
- if(empty($cancellation_rate))
632
- $cancellation_rate = pmpro_getCancellationRate($period, $levels);
633
-
634
- //average monthly spend
635
- if(empty($signups))
636
- return false;
637
-
638
- if($signups > 0)
639
- $ams = $mrr / $signups;
640
- else
641
- $ams = 0;
642
-
643
- if($cancellation_rate > 0)
644
- $ltv = $ams * (1/$cancellation_rate);
645
- else
646
- $ltv = $ams;
647
-
648
- return $ltv;
649
- }
650
-
651
- //delete transients when an order goes through
652
- function pmpro_report_memberships_delete_transients()
653
- {
654
- delete_transient("pmpro_report_mrr");
655
- delete_transient("pmpro_report_cancellation_rate");
656
- delete_transient("pmpro_report_memberships_cancellations");
657
- delete_transient("pmpro_report_memberships_signups");
658
- }
659
- add_action("pmpro_after_checkout", "pmpro_report_memberships_delete_transients");
660
- add_action("pmpro_updated_order", "pmpro_report_memberships_delete_transients");
1
+ <?php
2
+ /*
3
+ PMPro Report
4
+ Title: Membership Stats
5
+ Slug: memberships
6
+
7
+ For each report, add a line like:
8
+ global $pmpro_reports;
9
+ $pmpro_reports['slug'] = 'Title';
10
+
11
+ For each report, also write two functions:
12
+ * pmpro_report_{slug}_widget() to show up on the report homepage.
13
+ * pmpro_report_{slug}_page() to show up when users click on the report page widget.
14
+ */
15
+
16
+ global $pmpro_reports;
17
+
18
+ $pmpro_reports['memberships'] = __('Membership Stats', 'pmpro');
19
+
20
+ //queue Google Visualization JS on report page
21
+ function pmpro_report_memberships_init() {
22
+ if(is_admin() && isset($_REQUEST['report']) && $_REQUEST['report'] == "memberships" && isset($_REQUEST['page']) && $_REQUEST['page'] == "pmpro-reports")
23
+ wp_enqueue_script("jsapi", "https://www.google.com/jsapi");
24
+ }
25
+ add_action( 'init', 'pmpro_report_memberships_init' );
26
+
27
+
28
+ //widget
29
+ function pmpro_report_memberships_widget() {
30
+ global $wpdb;
31
+ ?>
32
+ <span id="pmpro_report_memberships">
33
+ <table class="wp-list-table widefat fixed striped">
34
+ <thead>
35
+ <tr>
36
+ <th scope="col">&nbsp;</th>
37
+ <th scope="col"><?php _e('Signups','pmpro'); ?></th>
38
+ <th scope="col"><?php _e('Cancellations','pmpro'); ?></th>
39
+ </tr>
40
+ </thead>
41
+ <tbody>
42
+ <tr>
43
+ <th scope="row"><?php _e('Today','pmpro'); ?></th>
44
+ <td><?php echo number_format_i18n(pmpro_getSignups('today')); ?></td>
45
+ <td><?php echo number_format_i18n(pmpro_getCancellations('today')); ?></td>
46
+ </tr>
47
+ <tr>
48
+ <th scope="row"><?php _e('This Month','pmpro'); ?></th>
49
+ <td><?php echo number_format_i18n(pmpro_getSignups('this month')); ?></td>
50
+ <td><?php echo number_format_i18n(pmpro_getCancellations('this month')); ?></td>
51
+ </tr>
52
+ <tr>
53
+ <th scope="row"><?php _e('This Year','pmpro'); ?></th>
54
+ <td><?php echo number_format_i18n(pmpro_getSignups('this year')); ?></td>
55
+ <td><?php echo number_format_i18n(pmpro_getCancellations('this year')); ?></td>
56
+ </tr>
57
+ <tr>
58
+ <th scope="row"><?php _e('All Time','pmpro'); ?></th>
59
+ <td><?php echo number_format_i18n(pmpro_getSignups('all time')); ?></td>
60
+ <td><?php echo number_format_i18n(pmpro_getCancellations('all time')); ?></td>
61
+ </tr>
62
+ </tbody>
63
+ </table>
64
+ </span>
65
+ <?php
66
+ }
67
+
68
+ function pmpro_report_memberships_page()
69
+ {
70
+ global $wpdb, $pmpro_currency_symbol;
71
+
72
+ //get values from form
73
+ if(isset($_REQUEST['type']))
74
+ $type = sanitize_text_field($_REQUEST['type']);
75
+ else
76
+ $type = "signup_v_cancel";
77
+
78
+ if(isset($_REQUEST['period']))
79
+ $period = sanitize_text_field($_REQUEST['period']);
80
+ else
81
+ $period = "monthly";
82
+
83
+ if(isset($_REQUEST['month']))
84
+ $month = intval($_REQUEST['month']);
85
+ else
86
+ $month = date("n");
87
+
88
+ $thisyear = date("Y");
89
+ if(isset($_REQUEST['year']))
90
+ $year = intval($_REQUEST['year']);
91
+ else
92
+ $year = date("Y");
93
+
94
+ if(isset($_REQUEST['level']))
95
+ $l = intval($_REQUEST['level']);
96
+ else
97
+ $l = "";
98
+
99
+ //calculate start date and how to group dates returned from DB
100
+ if($period == "daily")
101
+ {
102
+ $startdate = $year . '-' . substr("0" . $month, strlen($month) - 1, 2) . '-01';
103
+ $enddate = $year . '-' . substr("0" . $month, strlen($month) - 1, 2) . '-32';
104
+ $date_function = 'DAY';
105
+ }
106
+ elseif($period == "monthly")
107
+ {
108
+ $startdate = $year . '-01-01';
109
+ $enddate = strval(intval($year)+1) . '-01-01';
110
+ $date_function = 'MONTH';
111
+ }
112
+ elseif($period == "annual")
113
+ {
114
+ $startdate = '1960-01-01'; //all time
115
+ $date_function = 'YEAR';
116
+ }
117
+
118
+ //testing or live data
119
+ $gateway_environment = pmpro_getOption("gateway_environment");
120
+
121
+ //get data
122
+ if ( $type === "signup_v_cancel" ) {
123
+ $sqlQuery = "SELECT $date_function(startdate) as date, COUNT(DISTINCT user_id) as signups
124
+ FROM $wpdb->pmpro_memberships_users WHERE startdate >= '" . $startdate . "' ";
125
+
126
+ if(!empty($enddate))
127
+ $sqlQuery .= "AND startdate < '" . $enddate . "' ";
128
+ }
129
+ if ( $type === "mrr_ltv" ) {
130
+ // Get total revenue, number of months in system, and date
131
+ if ( $period == 'annual' )
132
+ $sqlQuery = "SELECT SUM(total) as total, COUNT(DISTINCT MONTH(timestamp)) as months, $date_function(timestamp) as date
133
+ FROM $wpdb->pmpro_membership_orders WHERE status NOT IN('refunded', 'review', 'token')
134
+ AND timestamp >= '" . $startdate . "' AND gateway_environment = '" . esc_sql($gateway_environment) . "' ";
135
+
136
+ if ( $period == 'monthly' )
137
+ $sqlQuery = "SELECT SUM(total) as total, $date_function(timestamp) as date
138
+ FROM $wpdb->pmpro_membership_orders WHERE status NOT IN('refunded', 'review', 'token')
139
+ AND timestamp >= '" . $startdate . "' AND gateway_environment = '" . esc_sql($gateway_environment) . "' ";
140
+
141
+ if(!empty($enddate))
142
+ $sqlQuery .= "AND timestamp < '" . $enddate . "' ";
143
+ }
144
+
145
+ if(!empty($l))
146
+ $sqlQuery .= "AND membership_id IN(" . $l . ") ";
147
+
148
+ $sqlQuery .= " GROUP BY date ORDER BY date ";
149
+
150
+ $dates = $wpdb->get_results($sqlQuery);
151
+
152
+ //fill in blanks in dates
153
+ $cols = array();
154
+ if($period == "daily")
155
+ {
156
+ $lastday = date("t", strtotime($startdate, current_time("timestamp")));
157
+
158
+ for($i = 1; $i <= $lastday; $i++)
159
+ {
160
+ // Signups vs. Cancellations
161
+ if ( $type === "signup_v_cancel" ) {
162
+ $cols[$i] = new stdClass();
163
+ $cols[$i]->signups = 0;
164
+ foreach($dates as $date)
165
+ {
166
+ if( $date->date == $i ) {
167
+ $cols[$i]->signups = $date->signups;
168
+ }
169
+ }
170
+ }
171
+ }
172
+ }
173
+ elseif($period == "monthly")
174
+ {
175
+ for($i = 1; $i < 13; $i++)
176
+ {
177
+ // Signups vs. Cancellations
178
+ if ( $type === "signup_v_cancel" ) {
179
+ $cols[$i] = new stdClass();
180
+ $cols[$i]->date = $i;
181
+ $cols[$i]->signups = 0;
182
+ foreach($dates as $date)
183
+ {
184
+ if( $date->date == $i ) {
185
+ $cols[$i]->date = $date->date;
186
+ $cols[$i]->signups = $date->signups;
187
+ }
188
+ }
189
+ }
190
+
191
+ // MRR & LTV
192
+ if ( $type === "mrr_ltv" ) {
193
+ $cols[$i] = new stdClass();
194
+ $cols[$i]->date = $i;
195
+ $cols[$i]->months = 1;
196
+ foreach($dates as $date)
197
+ {
198
+ if( $date->date == $i ) {
199
+ $cols[$i]->total = $date->total;
200
+ }
201
+ }
202
+ }
203
+ }
204
+ }
205
+ elseif($period == "annual") //annual
206
+ {
207
+ }
208
+
209
+ $dates = ( ! empty( $cols ) ) ? $cols : $dates;
210
+
211
+ // Signups vs. cancellations
212
+ if ( $type === "signup_v_cancel" )
213
+ {
214
+ $sqlQuery = "SELECT $date_function(mu1.modified) as date, COUNT(DISTINCT mu1.user_id) as cancellations
215
+ FROM $wpdb->pmpro_memberships_users mu1
216
+ LEFT JOIN $wpdb->pmpro_memberships_users mu2 ON mu1.user_id = mu2.user_id AND
217
+ mu2.modified > mu1.enddate AND
218
+ DATE_ADD(mu1.modified, INTERVAL 1 DAY) > mu2.startdate
219
+ WHERE mu1.status = 'inactive'
220
+ AND mu2.id IS NULL
221
+ AND mu1.startdate >= '" . $startdate . "'
222
+ AND mu1.startdate < '" . $enddate . "' ";
223
+
224
+ //restrict by level
225
+ if(!empty($l))
226
+ $sqlQuery .= "AND membership_id IN(" . $l . ") ";
227
+
228
+ $sqlQuery .= " GROUP BY date ORDER BY date ";
229
+
230
+ $cdates = $wpdb->get_results($sqlQuery, OBJECT_K);
231
+
232
+ foreach( $dates as &$date )
233
+ {
234
+ if(!empty($cdates) && !empty($cdates[$date->date]))
235
+ $date->cancellations = $cdates[$date->date]->cancellations;
236
+ else
237
+ $date->cancellations = 0;
238
+ }
239
+ }
240
+
241
+ // MRR & LTV
242
+ if ( $type === "mrr_ltv" && count( $dates ) === 1 ) {
243
+ $dummy_date = new stdClass();
244
+ $dummy_date->total = 0;
245
+ $dummy_date->months = 0;
246
+ $dummy_date->date = $dates[0]->date - 1;
247
+ array_unshift( $dates, $dummy_date ); // Add to beginning
248
+ }
249
+ ?>
250
+ <form id="posts-filter" method="get" action="">
251
+ <h2>
252
+ <?php _e('Membership Stats', 'pmpro');?>
253
+ </h2>
254
+ <ul class="subsubsub">
255
+ <li>
256
+ <?php _ex('Show', 'Dropdown label, e.g. Show Daily Revenue for January', 'pmpro')?>
257
+ <select id="period" name="period">
258
+ <option value="daily" <?php selected($period, "daily");?>><?php _e('Daily', 'pmpro');?></option>
259
+ <option value="monthly" <?php selected($period, "monthly");?>><?php _e('Monthly', 'pmpro');?></option>
260
+ <option value="annual" <?php selected($period, "annual");?>><?php _e('Annual', 'pmpro');?></option>
261
+ </select>
262
+ <select id="type" name="type">
263
+ <option value="signup_v_cancel" <?php selected($type, "signup_v_cancel");?>><?php _e('Signups vs. Cancellations', 'pmpro');?></option>
264
+ <?php /*
265
+ <option value="mrr_ltv" <?php selected($type, "mrr_ltv");?>><?php _e('MRR & LTV', 'pmpro');?></option>
266
+ */ ?>
267
+ </select>
268
+ <span id="for"><?php _ex('for', 'Dropdown label, e.g. Show Daily Revenue for January', 'pmpro')?></span>
269
+ <select id="month" name="month">
270
+ <?php for($i = 1; $i < 13; $i++) { ?>
271
+ <option value="<?php echo $i;?>" <?php selected($month, $i);?>><?php echo date("F", mktime(0, 0, 0, $i, 2));?></option>
272
+ <?php } ?>
273
+ </select>
274
+ <select id="year" name="year">
275
+ <?php for($i = $thisyear; $i > 2007; $i--) { ?>
276
+ <option value="<?php echo $i;?>" <?php selected($year, $i);?>><?php echo $i;?></option>
277
+ <?php } ?>
278
+ </select>
279
+ <span id="for"><?php _ex('for', 'Dropdown label, e.g. Show Daily Revenue for January', 'pmpro')?></span>
280
+ <select name="level">
281
+ <option value="" <?php if(!$l) { ?>selected="selected"<?php } ?>><?php _e('All Levels', 'pmpro');?></option>
282
+ <?php
283
+ $levels = $wpdb->get_results("SELECT id, name FROM $wpdb->pmpro_membership_levels ORDER BY name");
284
+ foreach($levels as $level)
285
+ {
286
+ ?>
287
+ <option value="<?php echo $level->id?>" <?php if($l == $level->id) { ?>selected="selected"<?php } ?>><?php echo $level->name?></option>
288
+ <?php
289
+ }
290
+ ?>
291
+ </select>
292
+
293
+ <input type="hidden" name="page" value="pmpro-reports" />
294
+ <input type="hidden" name="report" value="memberships" />
295
+ <input type="submit" value="<?php _ex('Generate Report', 'Submit button value.', 'pmpro');?>" />
296
+ </li>
297
+ </ul>
298
+
299
+ <div id="chart_div" style="clear: both; width: 100%; height: 500px;"></div>
300
+
301
+ <script>
302
+ //update month/year when period dropdown is changed
303
+ jQuery(document).ready(function() {
304
+ jQuery('#period').change(function() {
305
+ pmpro_ShowMonthOrYear();
306
+ });
307
+ });
308
+
309
+ function pmpro_ShowMonthOrYear()
310
+ {
311
+ var period = jQuery('#period').val();
312
+ if(period == 'daily')
313
+ {
314
+ jQuery('#for').show();
315
+ jQuery('#month').show();
316
+ jQuery('#year').show();
317
+ }
318
+ else if(period == 'monthly')
319
+ {
320
+ jQuery('#for').show();
321
+ jQuery('#month').hide();
322
+ jQuery('#year').show();
323
+ }
324
+ else
325
+ {
326
+ jQuery('#for').hide();
327
+ jQuery('#month').hide();
328
+ jQuery('#year').hide();
329
+ }
330
+ }
331
+
332
+ pmpro_ShowMonthOrYear();
333
+
334
+ //draw the chart
335
+ google.load("visualization", "1", {packages:["corechart"]});
336
+ google.setOnLoadCallback(drawChart);
337
+ function drawChart() {
338
+
339
+ var data = google.visualization.arrayToDataTable([
340
+ <?php if ( $type === "signup_v_cancel" ) : // Signups vs. cancellations ?>
341
+ ['<?php echo $date_function;?>', 'Signups', 'Cancellations'],
342
+ <?php foreach($dates as $key => $value) { ?>
343
+ ['<?php if($period == "monthly") echo date("M", mktime(0,0,0,$value->date,2)); else if($period == "daily") echo $key; else echo $value->date;?>', <?php echo $value->signups; ?>, <?php echo $value->cancellations; ?>],
344
+ <?php } ?>
345
+ <?php endif; ?>
346
+
347
+ <?php if ( $type === "mrr_ltv" ) : // Signups vs. cancellations ?>
348
+ ['<?php echo $date_function;?>', 'MRR', 'LTV'],
349
+ <?php foreach($dates as $key => $value) { ?>
350
+ ['<?php if($period == "monthly") echo date("M", mktime(0,0,0,$value->date,2)); else if($period == "daily") echo $key; else echo $value->date;?>', <?php echo (($mrr = $value->total / $value->months) && $mrr != 0) ? $mrr : 0; ?>, <?php echo pmpro_getLTV($period, NULL, $mrr ); ?>],
351
+ <?php } ?>
352
+ <?php endif; ?>
353
+ ]);
354
+
355
+ var options = {
356
+ colors: ['#0099c6', '#dc3912'],
357
+ hAxis: {title: '<?php echo $date_function;?>', titleTextStyle: {color: 'black'}, maxAlternation: 1},
358
+ vAxis: {color: 'green', titleTextStyle: {color: '#51a351'}},
359
+ };
360
+
361
+ <?php if ( $type === "signup_v_cancel" ) : // Signups vs. cancellations ?>
362
+ var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
363
+ <?php elseif ( $type === "mrr_ltv" ) : // MRR & LTV ?>
364
+
365
+ <?php
366
+ //prefix or suffix?
367
+ if(pmpro_getCurrencyPosition() == "right")
368
+ $position = "suffix";
369
+ else
370
+ $position = "prefix";
371
+ ?>
372
+
373
+ var formatter = new google.visualization.NumberFormat({<?php echo $position;?>: '<?php echo html_entity_decode($pmpro_currency_symbol);?>'});
374
+ formatter.format(data, 2);
375
+ var formatter = new google.visualization.NumberFormat({<?php echo $position;?>: '<?php echo html_entity_decode($pmpro_currency_symbol);?>'});
376
+ formatter.format(data, 1);
377
+
378
+ var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
379
+ <?php endif; ?>
380
+ chart.draw(data, options);
381
+ }
382
+ </script>
383
+
384
+ </form>
385
+ <?php
386
+ }
387
+
388
+
389
+
390
+ /*
391
+ Other code required for your reports. This file is loaded every time WP loads with PMPro enabled.
392
+ */
393
+
394
+ //get signups
395
+ function pmpro_getSignups($period = false, $levels = 'all')
396
+ {
397
+ //check for a transient
398
+ $cache = get_transient( 'pmpro_report_memberships_signups' );
399
+ if( ! empty( $cache ) && ! empty( $cache[$period] ) && ! empty( $cache[$period][$levels] ) )
400
+ return $cache[$period][$levels];
401
+
402
+ //a sale is an order with status = success
403
+ if( $period == 'today' )
404
+ $startdate = date(' Y-m-d' );
405
+ elseif( $period == 'this month')
406
+ $startdate = date( 'Y-m' ) . '-01';
407
+ elseif( $period == 'this year')
408
+ $startdate = date( 'Y' ) . '-01-01';
409
+ else
410
+ $startdate = '';
411
+
412
+
413
+ //build query
414
+ global $wpdb;
415
+
416
+ $sqlQuery = "SELECT COUNT(DISTINCT user_id) FROM $wpdb->pmpro_memberships_users WHERE startdate >= '" . $startdate . "' ";
417
+
418
+ //restrict by level
419
+ if(!empty($levels) && $levels != 'all')
420
+ $sqlQuery .= "AND membership_id IN(" . $levels . ") ";
421
+
422
+ $signups = $wpdb->get_var($sqlQuery);
423
+
424
+ //save in cache
425
+ if(!empty($cache) && !empty($cache[$period]))
426
+ $cache[$period][$levels] = $signups;
427
+ elseif(!empty($cache))
428
+ $cache[$period] = array($levels => $signups);
429
+ else
430
+ $cache = array($period => array($levels => $signups));
431
+
432
+ set_transient("pmpro_report_memberships_signups", $cache, 3600*24);
433
+
434
+ return $signups;
435
+ }
436
+
437
+ //get cancellations
438
+ function pmpro_getCancellations($period = false, $levels = 'all')
439
+ {
440
+ //check for a transient
441
+ $cache = get_transient( 'pmpro_report_memberships_cancellations' );
442
+ if( ! empty( $cache ) && ! empty( $cache[$period] ) && ! empty( $cache[$period][$levels] ) )
443
+ return $cache[$period][$levels];
444
+
445
+ //figure out start date
446
+ if( $period == 'today' )
447
+ $startdate = date(' Y-m-d' );
448
+ elseif( $period == 'this month')
449
+ $startdate = date( 'Y-m' ) . '-01';
450
+ elseif( $period == 'this year')
451
+ $startdate = date( 'Y' ) . '-01-01';
452
+ else
453
+ $startdate = '';
454
+
455
+ $startdate_plus_one = strtotime( $startdate . + ' + 1 day', current_time("timestamp") );
456
+
457
+ /*
458
+ build query.
459
+ cancellations are marked in the memberships users table with status = 'inactive'
460
+ we try to ignore cancellations when the user gets a new level with 24 hours (probably an upgrade or downgrade)
461
+ */
462
+ global $wpdb;
463
+
464
+ //$sqlQuery = "SELECT mu1.user_id, mu2.user_id FROM $wpdb->pmpro_memberships_users mu1 LEFT JOIN $wpdb->pmpro_memberships_users mu2 ON mu1.user_id = mu2.user_id AND mu2.status = 'inactive' AND mu2.startdate > mu1.startdate";
465
+ $sqlQuery = "SELECT COUNT(mu1.id)
466
+ FROM $wpdb->pmpro_memberships_users mu1
467
+ LEFT JOIN $wpdb->pmpro_memberships_users mu2 ON mu1.user_id = mu2.user_id AND
468
+ mu2.modified > mu1.enddate AND
469
+ DATE_ADD(mu1.modified, INTERVAL 1 DAY) > mu2.startdate
470
+ WHERE mu1.status = 'inactive'
471
+ AND mu2.id IS NULL
472
+ AND mu1.startdate >= '" . $startdate . "' ";
473
+
474
+ //restrict by level
475
+ if(!empty($levels) && $levels != 'all')
476
+ $sqlQuery .= "AND membership_id IN(" . $levels . ") ";
477
+
478
+ $cancellations = $wpdb->get_var($sqlQuery);
479
+
480
+ //save in cache
481
+ if(!empty($cache) && !empty($cache[$period]) && is_array($cache[$period]))
482
+ $cache[$period][$levels] = $cancellations;
483
+ elseif(!empty($cache))
484
+ $cache[$period] = array($levels => $cancellations);
485
+ else
486
+ $cache = array($period => array($levels => $cancellations));
487
+
488
+ set_transient("pmpro_report_memberships_cancellations", $cache, 3600*24);
489
+
490
+ return $cancellations;
491
+ }
492
+
493
+ //get MRR
494
+ function pmpro_getMRR($period, $levels = 'all')
495
+ {
496
+ //check for a transient
497
+ //$cache = get_transient("pmpro_report_mrr");
498
+ if(!empty($cache) && !empty($cache[$period]) && !empty($cache[$period][$levels]))
499
+ return $cache[$period][$levels];
500
+
501
+ //a sale is an order with status NOT IN refunded, review, token, error
502
+ if($period == "this month")
503
+ $startdate = date("Y-m") . "-01";
504
+ elseif($period == "this year")
505
+ $startdate = date("Y") . "-01-01";
506
+ else
507
+ $startdate = "";
508
+
509
+ $gateway_environment = pmpro_getOption("gateway_environment");
510
+
511
+ //build query
512
+ global $wpdb;
513
+ // Get total revenue
514
+ $sqlQuery = "SELECT SUM(total) FROM $wpdb->pmpro_membership_orders WHERE status NOT IN('refunded', 'review', 'token', 'error') AND timestamp >= '" . $startdate . "' AND gateway_environment = '" . esc_sql($gateway_environment) . "' ";
515
+
516
+ //restrict by level
517
+ if(!empty($levels) && $levels != 'all') {
518
+ $sqlQuery .= "AND membership_id IN(" . $levels . ") ";
519
+ }
520
+
521
+ $revenue = $wpdb->get_var($sqlQuery);
522
+
523
+ //when was the first order
524
+ $first_order_timestamp = $wpdb->get_var("SELECT UNIX_TIMESTAMP(`timestamp`) FROM $wpdb->pmpro_membership_orders WHERE `timestamp` IS NOT NULL AND `timestamp` > '0000-00-00 00:00:00' ORDER BY `timestamp` LIMIT 1");
525
+
526
+ //if we don't have a timestamp, we can't do this
527
+ if(empty($first_order_timestamp))
528
+ return false;
529
+
530
+ //how many months ago was the first order
531
+ $months = $wpdb->get_var("SELECT PERIOD_DIFF('" . date("Ym") . "', '" . date("Ym", $first_order_timestamp) . "')");
532
+
533
+ /* this works in PHP 5.3+ without using MySQL to get the diff
534
+ $date1 = new DateTime(date("Y-m-d", $first_order_timestamp));
535
+ $date2 = new DateTime(date("Y-m-d"));
536
+ $interval = $date1->diff($date2);
537
+ $years = intval($interval->format('%y'));
538
+ $months = $years*12 + intval($interval->format('%m'));
539
+ */
540
+
541
+ if($months > 0)
542
+ $mrr = $revenue / $months;
543
+ else
544
+ $mrr = 0;
545
+
546
+ //save in cache
547
+ if(!empty($cache) && !empty($cache[$period]))
548
+ $cache[$period][$levels] = $mrr;
549
+ elseif(!empty($cache))
550
+ $cache[$period] = array($levels => $mrr);
551
+ else
552
+ $cache = array($period => array($levels => $mrr));
553
+
554
+ set_transient("pmpro_report_mrr", $cache, 3600*24);
555
+
556
+ return $mrr;
557
+ }
558
+
559
+ //get Cancellation Rate
560
+ function pmpro_getCancellationRate($period, $levels = 'all')
561
+ {
562
+ //check for a transient
563
+ $cache = get_transient("pmpro_report_cancellation_rate");
564
+ if(!empty($cache) && !empty($cache[$period]) && !empty($cache[$period][$levels]))
565
+ return $cache[$period][$levels];
566
+
567
+ $signups = pmpro_getSignups($period, $levels);
568
+ $cancellations = pmpro_getCancellations($period, $levels);
569
+
570
+ if(empty($signups))
571
+ return false;
572
+
573
+ $rate = number_format(($cancellations / $signups)*100, 2);
574
+
575
+ //save in cache
576
+ if(!empty($cache) && !empty($cache[$period]))
577
+ $cache[$period][$levels] = $rate;
578
+ elseif(!empty($cache))
579
+ $cache[$period] = array($levels => $rate);
580
+ else
581
+ $cache = array($period => array($levels => $rate));
582
+
583
+ set_transient("pmpro_report_cancellation_rate", $cache, 3600*24);
584
+
585
+ return $rate;
586
+ }
587
+
588
+ //get LTV
589
+ function pmpro_getLTV($period, $levels = 'all', $mrr = NULL, $signups = NULL, $cancellation_rate = NULL)
590
+ {
591
+ if(empty($mrr))
592
+ $mrr = pmpro_getMRR($period, $levels);
593
+ if(empty($signups))
594
+ $signups = pmpro_getSignups($period, $levels);
595
+ if(empty($cancellation_rate))
596
+ $cancellation_rate = pmpro_getCancellationRate($period, $levels);
597
+
598
+ //average monthly spend
599
+ if(empty($signups))
600
+ return false;
601
+
602
+ if($signups > 0)
603
+ $ams = $mrr / $signups;
604
+ else
605
+ $ams = 0;
606
+
607
+ if($cancellation_rate > 0)
608
+ $ltv = $ams * (1/$cancellation_rate);
609
+ else
610
+ $ltv = $ams;
611
+
612
+ return $ltv;
613
+ }
614
+
615
+ //delete transients when an order goes through
616
+ function pmpro_report_memberships_delete_transients()
617
+ {
618
+ delete_transient("pmpro_report_mrr");
619
+ delete_transient("pmpro_report_cancellation_rate");
620
+ delete_transient("pmpro_report_memberships_cancellations");
621
+ delete_transient("pmpro_report_memberships_signups");
622
+ }
623
+ add_action("pmpro_after_checkout", "pmpro_report_memberships_delete_transients");
624
+ add_action("pmpro_updated_order", "pmpro_report_memberships_delete_transients");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
adminpages/reports/sales.php CHANGED
@@ -1,406 +1,415 @@
1
- <?php
2
- /*
3
- PMPro Report
4
- Title: Sales
5
- Slug: sales
6
-
7
- For each report, add a line like:
8
- global $pmpro_reports;
9
- $pmpro_reports['slug'] = 'Title';
10
-
11
- For each report, also write two functions:
12
- * pmpro_report_{slug}_widget() to show up on the report homepage.
13
- * pmpro_report_{slug}_page() to show up when users click on the report page widget.
14
- */
15
- global $pmpro_reports;
16
- $gateway_environment = pmpro_getOption("gateway_environment");
17
- if($gateway_environment == "sandbox")
18
- $pmpro_reports['sales'] = __('Sales and Revenue (Testing/Sandbox)', 'pmpro');
19
- else
20
- $pmpro_reports['sales'] = __('Sales and Revenue', 'pmpro');
21
-
22
- //queue Google Visualization JS on report page
23
- function pmpro_report_sales_init()
24
- {
25
- if(is_admin() && isset($_REQUEST['report']) && $_REQUEST['report'] == "sales" && isset($_REQUEST['page']) && $_REQUEST['page'] == "pmpro-reports")
26
- {
27
- wp_enqueue_script("jsapi", "https://www.google.com/jsapi");
28
- }
29
- }
30
- add_action("init", "pmpro_report_sales_init");
31
-
32
- //widget
33
- function pmpro_report_sales_widget()
34
- {
35
- global $wpdb;
36
- ?>
37
- <style>
38
- #pmpro_report_sales div {text-align: center;}
39
- #pmpro_report_sales em {display: block; font-style: normal; font-size: 2em; margin: 5px;}
40
- </style>
41
- <span id="#pmpro_report_sales">
42
- <div style="width: 25%; float: left;">
43
- <em><?php echo pmpro_getSales("all time");?></em>
44
- <label>All Time</label>
45
- <em><?php echo pmpro_formatPrice(pmpro_getRevenue("all time"));?></em>
46
- </div>
47
- <div style="width: 25%; float: left;">
48
- <em><?php echo pmpro_getSales("this year");?></em>
49
- <label>This Year</label>
50
- <em><?php echo pmpro_formatPrice(pmpro_getRevenue("this year"));?></em>
51
- </div>
52
- <div style="width: 25%; float: left;">
53
- <em><?php echo pmpro_getSales("this month");?></em>
54
- <label>This Month</label>
55
- <em><?php echo pmpro_formatPrice(pmpro_getRevenue("this month"));?></em>
56
- </div>
57
- <div style="width: 25%; float: left;">
58
- <em><?php echo pmpro_getSales("today");?></em>
59
- <label>Today</label>
60
- <em><?php echo pmpro_formatPrice(pmpro_getRevenue("today"));?></em>
61
- </div>
62
- <div class="clear"></div>
63
- </span>
64
- <?php
65
- }
66
-
67
- function pmpro_report_sales_page()
68
- {
69
- global $wpdb, $pmpro_currency_symbol, $pmpro_currency, $pmpro_currencies;
70
-
71
- //get values from form
72
- if(isset($_REQUEST['type']))
73
- $type = sanitize_text_field($_REQUEST['type']);
74
- else
75
- $type = "revenue";
76
-
77
- if($type == "sales")
78
- $type_function = "COUNT";
79
- else
80
- $type_function = "SUM";
81
-
82
- if(isset($_REQUEST['period']))
83
- $period = sanitize_text_field($_REQUEST['period']);
84
- else
85
- $period = "daily";
86
-
87
- if(isset($_REQUEST['month']))
88
- $month = intval($_REQUEST['month']);
89
- else
90
- $month = date("n", current_time('timestamp'));
91
-
92
- $thisyear = date("Y", current_time('timestamp'));
93
- if(isset($_REQUEST['year']))
94
- $year = intval($_REQUEST['year']);
95
- else
96
- $year = $thisyear;
97
-
98
- if(isset($_REQUEST['level']))
99
- $l = intval($_REQUEST['level']);
100
- else
101
- $l = "";
102
-
103
- //calculate start date and how to group dates returned from DB
104
- if($period == "daily")
105
- {
106
- $startdate = $year . '-' . substr("0" . $month, strlen($month) - 1, 2) . '-01';
107
- $enddate = $year . '-' . substr("0" . $month, strlen($month) - 1, 2) . '-32';
108
- $date_function = 'DAY';
109
- }
110
- elseif($period == "monthly")
111
- {
112
- $startdate = $year . '-01-01';
113
- $enddate = strval(intval($year)+1) . '-01-01';
114
- $date_function = 'MONTH';
115
- }
116
- else
117
- {
118
- $startdate = '1960-01-01'; //all time
119
- $date_function = 'YEAR';
120
- }
121
-
122
- //testing or live data
123
- $gateway_environment = pmpro_getOption("gateway_environment");
124
-
125
- //get data
126
- $sqlQuery = "SELECT $date_function(timestamp) as date, $type_function(total) as value FROM $wpdb->pmpro_membership_orders WHERE timestamp >= '" . $startdate . "' AND status NOT IN('refunded', 'review', 'token', 'error') AND gateway_environment = '" . esc_sql($gateway_environment) . "' ";
127
-
128
- if(!empty($enddate))
129
- $sqlQuery .= "AND timestamp < '" . $enddate . "' ";
130
-
131
- if(!empty($l))
132
- $sqlQuery .= "AND membership_id IN(" . $l . ") ";
133
-
134
- $sqlQuery .= " GROUP BY date ORDER BY date ";
135
-
136
- $dates = $wpdb->get_results($sqlQuery);
137
-
138
- //fill in blanks in dates
139
- $cols = array();
140
- if($period == "daily")
141
- {
142
- $lastday = date("t", strtotime($startdate, current_time("timestamp")));
143
-
144
- for($i = 1; $i <= $lastday; $i++)
145
- {
146
- $cols[$i] = 0;
147
- foreach($dates as $date)
148
- {
149
- if($date->date == $i)
150
- $cols[$i] = $date->value;
151
- }
152
- }
153
- }
154
- elseif($period == "monthly")
155
- {
156
- for($i = 1; $i < 13; $i++)
157
- {
158
- $cols[$i] = 0;
159
- foreach($dates as $date)
160
- {
161
- if($date->date == $i)
162
- $cols[$i] = $date->value;
163
- }
164
- }
165
- }
166
- else //annual
167
- {
168
- //get min and max years
169
- $min = 9999;
170
- $max = 0;
171
- foreach($dates as $date)
172
- {
173
- $min = min($min, $date->date);
174
- $max = max($max, $date->date);
175
- }
176
-
177
- for($i = $min; $i <= $max; $i++)
178
- {
179
- foreach($dates as $date)
180
- {
181
- if($date->date == $i)
182
- $cols[$i] = $date->value;
183
- }
184
- }
185
- }
186
- ?>
187
- <form id="posts-filter" method="get" action="">
188
- <h2>
189
- <?php _e('Sales and Revenue', 'pmpro');?>
190
- </h2>
191
-
192
- <div class="tablenav top">
193
- <?php _ex('Show', 'Dropdown label, e.g. Show Daily Revenue for January', 'pmpro')?>
194
- <select id="period" name="period">
195
- <option value="daily" <?php selected($period, "daily");?>><?php _e('Daily', 'pmpro');?></option>
196
- <option value="monthly" <?php selected($period, "monthly");?>><?php _e('Monthly', 'pmpro');?></option>
197
- <option value="annual" <?php selected($period, "annual");?>><?php _e('Annual', 'pmpro');?></option>
198
- </select>
199
- <select name="type">
200
- <option value="revenue" <?php selected($type, "revenue");?>><?php _e('Revenue', 'pmpro');?></option>
201
- <option value="sales" <?php selected($type, "sales");?>><?php _e('Sales', 'pmpro');?></option>
202
- </select>
203
- <span id="for"><?php _ex('for', 'Dropdown label, e.g. Show Daily Revenue for January', 'pmpro')?></span>
204
- <select id="month" name="month">
205
- <?php for($i = 1; $i < 13; $i++) { ?>
206
- <option value="<?php echo $i;?>" <?php selected($month, $i);?>><?php echo date("F", mktime(0, 0, 0, $i, 2));?></option>
207
- <?php } ?>
208
- </select>
209
- <select id="year" name="year">
210
- <?php for($i = $thisyear; $i > 2007; $i--) { ?>
211
- <option value="<?php echo $i;?>" <?php selected($year, $i);?>><?php echo $i;?></option>
212
- <?php } ?>
213
- </select>
214
- <span id="for"><?php _ex('for', 'Dropdown label, e.g. Show Daily Revenue for January', 'pmpro')?></span>
215
- <select name="level">
216
- <option value="" <?php if(!$l) { ?>selected="selected"<?php } ?>><?php _e('All Levels', 'pmpro');?></option>
217
- <?php
218
- $levels = $wpdb->get_results("SELECT id, name FROM $wpdb->pmpro_membership_levels ORDER BY name");
219
- foreach($levels as $level)
220
- {
221
- ?>
222
- <option value="<?php echo $level->id?>" <?php if($l == $level->id) { ?>selected="selected"<?php } ?>><?php echo $level->name?></option>
223
- <?php
224
- }
225
- ?>
226
- </select>
227
-
228
- <input type="hidden" name="page" value="pmpro-reports" />
229
- <input type="hidden" name="report" value="sales" />
230
- <input type="submit" class="button action" value="<?php _ex('Generate Report', 'Submit button value.', 'pmpro');?>" />
231
- </div>
232
-
233
- <div id="chart_div" style="clear: both; width: 100%; height: 500px;"></div>
234
-
235
- <script>
236
- //update month/year when period dropdown is changed
237
- jQuery(document).ready(function() {
238
- jQuery('#period').change(function() {
239
- pmpro_ShowMonthOrYear();
240
- });
241
- });
242
-
243
- function pmpro_ShowMonthOrYear()
244
- {
245
- var period = jQuery('#period').val();
246
- if(period == 'daily')
247
- {
248
- jQuery('#for').show();
249
- jQuery('#month').show();
250
- jQuery('#year').show();
251
- }
252
- else if(period == 'monthly')
253
- {
254
- jQuery('#for').show();
255
- jQuery('#month').hide();
256
- jQuery('#year').show();
257
- }
258
- else
259
- {
260
- jQuery('#for').hide();
261
- jQuery('#month').hide();
262
- jQuery('#year').hide();
263
- }
264
- }
265
-
266
- pmpro_ShowMonthOrYear();
267
-
268
- //draw the chart
269
- google.load("visualization", "1", {packages:["corechart"]});
270
- google.setOnLoadCallback(drawChart);
271
- function drawChart() {
272
-
273
- var data = google.visualization.arrayToDataTable([
274
- ['<?php echo $date_function;?>', '<?php echo ucwords($type);?>'],
275
- <?php foreach($cols as $date => $value) { ?>
276
- ['<?php if($period == "monthly") echo date("M", mktime(0,0,0,$date,2)); else echo $date;?>', <?php echo $value;?>],
277
- <?php } ?>
278
- ]);
279
-
280
- var options = {
281
- colors: ['#51a351', '#387038'],
282
- hAxis: {title: '<?php echo $date_function;?>', titleTextStyle: {color: 'black'}, maxAlternation: 1},
283
- vAxis: {color: 'green', titleTextStyle: {color: '#51a351'}},
284
- };
285
-
286
- <?php
287
- if($type != "sales")
288
- {
289
- if(pmpro_getCurrencyPosition() == "right")
290
- $position = "suffix";
291
- else
292
- $position = "prefix";
293
- ?>
294
- var formatter = new google.visualization.NumberFormat({<?php echo $position;?>: '<?php echo html_entity_decode($pmpro_currency_symbol);?>'});
295
- formatter.format(data, 1);
296
- <?php
297
- }
298
- ?>
299
-
300
- var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
301
- chart.draw(data, options);
302
- }
303
- </script>
304
-
305
- </form>
306
- <?php
307
- }
308
-
309
- /*
310
- Other code required for your reports. This file is loaded every time WP loads with PMPro enabled.
311
- */
312
-
313
- //get sales
314
- function pmpro_getSales($period, $levels = NULL)
315
- {
316
- //check for a transient
317
- $cache = get_transient("pmpro_report_sales");
318
- if(!empty($cache) && !empty($cache[$period]) && !empty($cache[$period][$levels]))
319
- return $cache[$period][$levels];
320
-
321
- //a sale is an order with status NOT IN('refunded', 'review', 'token', 'error')
322
- if($period == "today")
323
- $startdate = date("Y-m-d", current_time('timestamp'));
324
- elseif($period == "this month")
325
- $startdate = date("Y-m", current_time('timestamp')) . "-01";
326
- elseif($period == "this year")
327
- $startdate = date("Y", current_time('timestamp')) . "-01-01";
328
- else
329
- $startdate = "";
330
-
331
- $gateway_environment = pmpro_getOption("gateway_environment");
332
-
333
- //build query
334
- global $wpdb;
335
- $sqlQuery = "SELECT COUNT(*) FROM $wpdb->pmpro_membership_orders WHERE status NOT IN('refunded', 'review', 'token', 'error') AND timestamp >= '" . $startdate . "' AND gateway_environment = '" . esc_sql($gateway_environment) . "' ";
336
-
337
- //restrict by level
338
- if(!empty($levels))
339
- $sqlQuery .= "AND membership_id IN(" . $levels . ") ";
340
-
341
- $sales = $wpdb->get_var($sqlQuery);
342
-
343
- //save in cache
344
- if(!empty($cache) && !empty($cache[$period]))
345
- $cache[$period][$levels] = $sales;
346
- elseif(!empty($cache))
347
- $cache[$period] = array($levels => $sales);
348
- else
349
- $cache = array($period => array($levels => $sales));
350
-
351
- set_transient("pmpro_report_sales", $cache, 3600*24);
352
-
353
- return $sales;
354
- }
355
-
356
- //get revenue
357
- function pmpro_getRevenue($period, $levels = NULL)
358
- {
359
- //check for a transient
360
- $cache = get_transient("pmpro_report_revenue");
361
- if(!empty($cache) && !empty($cache[$period]) && !empty($cache[$period][$levels]))
362
- return $cache[$period][$levels];
363
-
364
- //a sale is an order with status NOT IN('refunded', 'review', 'token', 'error')
365
- if($period == "today")
366
- $startdate = date("Y-m-d", current_time('timestamp'));
367
- elseif($period == "this month")
368
- $startdate = date("Y-m", current_time('timestamp')) . "-01";
369
- elseif($period == "this year")
370
- $startdate = date("Y", current_time('timestamp')) . "-01-01";
371
- else
372
- $startdate = "";
373
-
374
- $gateway_environment = pmpro_getOption("gateway_environment");
375
-
376
- //build query
377
- global $wpdb;
378
- $sqlQuery = "SELECT SUM(total) FROM $wpdb->pmpro_membership_orders WHERE status NOT IN('refunded', 'review', 'token', 'error') AND timestamp >= '" . $startdate . "' AND gateway_environment = '" . esc_sql($gateway_environment) . "' ";
379
-
380
- //restrict by level
381
- if(!empty($levels))
382
- $sqlQuery .= "AND membership_id IN(" . $levels . ") ";
383
-
384
- $revenue = $wpdb->get_var($sqlQuery);
385
-
386
- //save in cache
387
- if(!empty($cache) && !empty($cache[$period]))
388
- $cache[$period][$levels] = $revenue;
389
- elseif(!empty($cache))
390
- $cache[$period] = array($levels => $revenue);
391
- else
392
- $cache = array($period => array($levels => $revenue));
393
-
394
- set_transient("pmpro_report_revenue", $cache, 3600*24);
395
-
396
- return $revenue;
397
- }
398
-
399
- //delete transients when an order goes through
400
- function pmpro_report_sales_delete_transients()
401
- {
402
- delete_transient("pmpro_report_sales");
403
- delete_transient("pmpro_report_revenue");
404
- }
405
- add_action("pmpro_after_checkout", "pmpro_report_sales_delete_transients");
406
- add_action("pmpro_updated_order", "pmpro_report_sales_delete_transients");
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ PMPro Report
4
+ Title: Sales
5
+ Slug: sales
6
+
7
+ For each report, add a line like:
8
+ global $pmpro_reports;
9
+ $pmpro_reports['slug'] = 'Title';
10
+
11
+ For each report, also write two functions:
12
+ * pmpro_report_{slug}_widget() to show up on the report homepage.
13
+ * pmpro_report_{slug}_page() to show up when users click on the report page widget.
14
+ */
15
+ global $pmpro_reports;
16
+ $gateway_environment = pmpro_getOption("gateway_environment");
17
+ if($gateway_environment == "sandbox")
18
+ $pmpro_reports['sales'] = __('Sales and Revenue (Testing/Sandbox)', 'pmpro');
19
+ else
20
+ $pmpro_reports['sales'] = __('Sales and Revenue', 'pmpro');
21
+
22
+ //queue Google Visualization JS on report page
23
+ function pmpro_report_sales_init()
24
+ {
25
+ if(is_admin() && isset($_REQUEST['report']) && $_REQUEST['report'] == "sales" && isset($_REQUEST['page']) && $_REQUEST['page'] == "pmpro-reports")
26
+ {
27
+ wp_enqueue_script("jsapi", "https://www.google.com/jsapi");
28
+ }
29
+ }
30
+ add_action("init", "pmpro_report_sales_init");
31
+
32
+ //widget
33
+ function pmpro_report_sales_widget()
34
+ {
35
+ global $wpdb;
36
+ ?>
37
+ <style>
38
+ #pmpro_report_sales tbody td:last-child {text-align: right; }
39
+ </style>
40
+ <span id="pmpro_report_sales">
41
+ <table class="wp-list-table widefat fixed striped">
42
+ <thead>
43
+ <tr>
44
+ <th scope="col">&nbsp;</th>
45
+ <th scope="col"><?php _e('Sales','pmpro'); ?></th>
46
+ <th scope="col"><?php _e('Revenue','pmpro'); ?></th>
47
+ </tr>
48
+ </thead>
49
+ <tbody>
50
+ <tr>
51
+ <th scope="row"><?php _e('Today','pmpro'); ?></th>
52
+ <td><?php echo number_format_i18n(pmpro_getSales("today")); ?></td>
53
+ <td><?php echo pmpro_formatPrice(pmpro_getRevenue("today"));?></td>
54
+ </tr>
55
+ <tr>
56
+ <th scope="row"><?php _e('This Month','pmpro'); ?></th>
57
+ <td><?php echo number_format_i18n(pmpro_getSales("this month")); ?></td>
58
+ <td><?php echo pmpro_formatPrice(pmpro_getRevenue("this month"));?></td>
59
+ </tr>
60
+ <tr>
61
+ <th scope="row"><?php _e('This Year','pmpro'); ?></th>
62
+ <td><?php echo number_format_i18n(pmpro_getSales("this year")); ?></td>
63
+ <td><?php echo pmpro_formatPrice(pmpro_getRevenue("this year"));?></td>
64
+ </tr>
65
+ <tr>
66
+ <th scope="row"><?php _e('All Time','pmpro'); ?></th>
67
+ <td><?php echo number_format_i18n(pmpro_getSales("all time")); ?></td>
68
+ <td><?php echo pmpro_formatPrice(pmpro_getRevenue("all time"));?></td>
69
+ </tr>
70
+ </tbody>
71
+ </table>
72
+ </span>
73
+ <?php
74
+ }
75
+
76
+ function pmpro_report_sales_page()
77
+ {
78
+ global $wpdb, $pmpro_currency_symbol, $pmpro_currency, $pmpro_currencies;
79
+
80
+ //get values from form
81
+ if(isset($_REQUEST['type']))
82
+ $type = sanitize_text_field($_REQUEST['type']);
83
+ else
84
+ $type = "revenue";
85
+
86
+ if($type == "sales")
87
+ $type_function = "COUNT";
88
+ else
89
+ $type_function = "SUM";
90
+
91
+ if(isset($_REQUEST['period']))
92
+ $period = sanitize_text_field($_REQUEST['period']);
93
+ else
94
+ $period = "daily";
95
+
96
+ if(isset($_REQUEST['month']))
97
+ $month = intval($_REQUEST['month']);
98
+ else
99
+ $month = date("n", current_time('timestamp'));
100
+
101
+ $thisyear = date("Y", current_time('timestamp'));
102
+ if(isset($_REQUEST['year']))
103
+ $year = intval($_REQUEST['year']);
104
+ else
105
+ $year = $thisyear;
106
+
107
+ if(isset($_REQUEST['level']))
108
+ $l = intval($_REQUEST['level']);
109
+ else
110
+ $l = "";
111
+
112
+ //calculate start date and how to group dates returned from DB
113
+ if($period == "daily")
114
+ {
115
+ $startdate = $year . '-' . substr("0" . $month, strlen($month) - 1, 2) . '-01';
116
+ $enddate = $year . '-' . substr("0" . $month, strlen($month) - 1, 2) . '-32';
117
+ $date_function = 'DAY';
118
+ }
119
+ elseif($period == "monthly")
120
+ {
121
+ $startdate = $year . '-01-01';
122
+ $enddate = strval(intval($year)+1) . '-01-01';
123
+ $date_function = 'MONTH';
124
+ }
125
+ else
126
+ {
127
+ $startdate = '1960-01-01'; //all time
128
+ $date_function = 'YEAR';
129
+ }
130
+
131
+ //testing or live data
132
+ $gateway_environment = pmpro_getOption("gateway_environment");
133
+
134
+ //get data
135
+ $sqlQuery = "SELECT $date_function(timestamp) as date, $type_function(total) as value FROM $wpdb->pmpro_membership_orders WHERE timestamp >= '" . $startdate . "' AND status NOT IN('refunded', 'review', 'token', 'error') AND gateway_environment = '" . esc_sql($gateway_environment) . "' ";
136
+
137
+ if(!empty($enddate))
138
+ $sqlQuery .= "AND timestamp < '" . $enddate . "' ";
139
+
140
+ if(!empty($l))
141
+ $sqlQuery .= "AND membership_id IN(" . $l . ") ";
142
+
143
+ $sqlQuery .= " GROUP BY date ORDER BY date ";
144
+
145
+ $dates = $wpdb->get_results($sqlQuery);
146
+
147
+ //fill in blanks in dates
148
+ $cols = array();
149
+ if($period == "daily")
150
+ {
151
+ $lastday = date("t", strtotime($startdate, current_time("timestamp")));
152
+
153
+ for($i = 1; $i <= $lastday; $i++)
154
+ {
155
+ $cols[$i] = 0;
156
+ foreach($dates as $date)
157
+ {
158
+ if($date->date == $i)
159
+ $cols[$i] = $date->value;
160
+ }
161
+ }
162
+ }
163
+ elseif($period == "monthly")
164
+ {
165
+ for($i = 1; $i < 13; $i++)
166
+ {
167
+ $cols[$i] = 0;
168
+ foreach($dates as $date)
169
+ {
170
+ if($date->date == $i)
171
+ $cols[$i] = $date->value;
172
+ }
173
+ }
174
+ }
175
+ else //annual
176
+ {
177
+ //get min and max years
178
+ $min = 9999;
179
+ $max = 0;
180
+ foreach($dates as $date)
181
+ {
182
+ $min = min($min, $date->date);
183
+ $max = max($max, $date->date);
184
+ }
185
+
186
+ for($i = $min; $i <= $max; $i++)
187
+ {
188
+ foreach($dates as $date)
189
+ {
190
+ if($date->date == $i)
191
+ $cols[$i] = $date->value;
192
+ }
193
+ }
194
+ }
195
+ ?>
196
+ <form id="posts-filter" method="get" action="">
197
+ <h2>
198
+ <?php _e('Sales and Revenue', 'pmpro');?>
199
+ </h2>
200
+
201
+ <div class="tablenav top">
202
+ <?php _ex('Show', 'Dropdown label, e.g. Show Daily Revenue for January', 'pmpro')?>
203
+ <select id="period" name="period">
204
+ <option value="daily" <?php selected($period, "daily");?>><?php _e('Daily', 'pmpro');?></option>
205
+ <option value="monthly" <?php selected($period, "monthly");?>><?php _e('Monthly', 'pmpro');?></option>
206
+ <option value="annual" <?php selected($period, "annual");?>><?php _e('Annual', 'pmpro');?></option>
207
+ </select>
208
+ <select name="type">
209
+ <option value="revenue" <?php selected($type, "revenue");?>><?php _e('Revenue', 'pmpro');?></option>
210
+ <option value="sales" <?php selected($type, "sales");?>><?php _e('Sales', 'pmpro');?></option>
211
+ </select>
212
+ <span id="for"><?php _ex('for', 'Dropdown label, e.g. Show Daily Revenue for January', 'pmpro')?></span>
213
+ <select id="month" name="month">
214
+ <?php for($i = 1; $i < 13; $i++) { ?>
215
+ <option value="<?php echo $i;?>" <?php selected($month, $i);?>><?php echo date("F", mktime(0, 0, 0, $i, 2));?></option>
216
+ <?php } ?>
217
+ </select>
218
+ <select id="year" name="year">
219
+ <?php for($i = $thisyear; $i > 2007; $i--) { ?>
220
+ <option value="<?php echo $i;?>" <?php selected($year, $i);?>><?php echo $i;?></option>
221
+ <?php } ?>
222
+ </select>
223
+ <span id="for"><?php _ex('for', 'Dropdown label, e.g. Show Daily Revenue for January', 'pmpro')?></span>
224
+ <select name="level">
225
+ <option value="" <?php if(!$l) { ?>selected="selected"<?php } ?>><?php _e('All Levels', 'pmpro');?></option>
226
+ <?php
227
+ $levels = $wpdb->get_results("SELECT id, name FROM $wpdb->pmpro_membership_levels ORDER BY name");
228
+ foreach($levels as $level)
229
+ {
230
+ ?>
231
+ <option value="<?php echo $level->id?>" <?php if($l == $level->id) { ?>selected="selected"<?php } ?>><?php echo $level->name?></option>
232
+ <?php
233
+ }
234
+ ?>
235
+ </select>
236
+
237
+ <input type="hidden" name="page" value="pmpro-reports" />
238
+ <input type="hidden" name="report" value="sales" />
239
+ <input type="submit" class="button action" value="<?php _ex('Generate Report', 'Submit button value.', 'pmpro');?>" />
240
+ </div>
241
+
242
+ <div id="chart_div" style="clear: both; width: 100%; height: 500px;"></div>
243
+
244
+ <script>
245
+ //update month/year when period dropdown is changed
246
+ jQuery(document).ready(function() {
247
+ jQuery('#period').change(function() {
248
+ pmpro_ShowMonthOrYear();
249
+ });
250
+ });
251
+
252
+ function pmpro_ShowMonthOrYear()
253
+ {
254
+ var period = jQuery('#period').val();
255
+ if(period == 'daily')
256
+ {
257
+ jQuery('#for').show();
258
+ jQuery('#month').show();
259
+ jQuery('#year').show();
260
+ }
261
+ else if(period == 'monthly')
262
+ {
263
+ jQuery('#for').show();
264
+ jQuery('#month').hide();
265
+ jQuery('#year').show();
266
+ }
267
+ else
268
+ {
269
+ jQuery('#for').hide();
270
+ jQuery('#month').hide();
271
+ jQuery('#year').hide();
272
+ }
273
+ }
274
+
275
+ pmpro_ShowMonthOrYear();
276
+
277
+ //draw the chart
278
+ google.load("visualization", "1", {packages:["corechart"]});
279
+ google.setOnLoadCallback(drawChart);
280
+ function drawChart() {
281
+
282
+ var data = google.visualization.arrayToDataTable([
283
+ ['<?php echo $date_function;?>', '<?php echo ucwords($type);?>'],
284
+ <?php foreach($cols as $date => $value) { ?>
285
+ ['<?php if($period == "monthly") echo date("M", mktime(0,0,0,$date,2)); else echo $date;?>', <?php echo $value;?>],
286
+ <?php } ?>
287
+ ]);
288
+
289
+ var options = {
290
+ colors: ['#51a351', '#387038'],
291
+ hAxis: {title: '<?php echo $date_function;?>', titleTextStyle: {color: 'black'}, maxAlternation: 1},
292
+ vAxis: {color: 'green', titleTextStyle: {color: '#51a351'}},
293
+ };
294
+
295
+ <?php
296
+ if($type != "sales")
297
+ {
298
+ if(pmpro_getCurrencyPosition() == "right")
299
+ $position = "suffix";
300
+ else
301
+ $position = "prefix";
302
+ ?>
303
+ var formatter = new google.visualization.NumberFormat({<?php echo $position;?>: '<?php echo html_entity_decode($pmpro_currency_symbol);?>'});
304
+ formatter.format(data, 1);
305
+ <?php
306
+ }
307
+ ?>
308
+
309
+ var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
310
+ chart.draw(data, options);
311
+ }
312
+ </script>
313
+
314
+ </form>
315
+ <?php
316
+ }
317
+
318
+ /*
319
+ Other code required for your reports. This file is loaded every time WP loads with PMPro enabled.
320
+ */
321
+
322
+ //get sales
323
+ function pmpro_getSales($period, $levels = NULL)
324
+ {
325
+ //check for a transient
326
+ $cache = get_transient("pmpro_report_sales");
327
+ if(!empty($cache) && !empty($cache[$period]) && !empty($cache[$period][$levels]))
328
+ return $cache[$period][$levels];
329
+
330
+ //a sale is an order with status NOT IN('refunded', 'review', 'token', 'error')
331
+ if($period == "today")
332
+ $startdate = date("Y-m-d", current_time('timestamp'));
333
+ elseif($period == "this month")
334
+ $startdate = date("Y-m", current_time('timestamp')) . "-01";
335
+ elseif($period == "this year")
336
+ $startdate = date("Y", current_time('timestamp')) . "-01-01";
337
+ else
338
+ $startdate = "";
339
+
340
+ $gateway_environment = pmpro_getOption("gateway_environment");
341
+
342
+ //build query
343
+ global $wpdb;
344
+ $sqlQuery = "SELECT COUNT(*) FROM $wpdb->pmpro_membership_orders WHERE status NOT IN('refunded', 'review', 'token', 'error') AND timestamp >= '" . $startdate . "' AND gateway_environment = '" . esc_sql($gateway_environment) . "' ";
345
+
346
+ //restrict by level
347
+ if(!empty($levels))
348
+ $sqlQuery .= "AND membership_id IN(" . $levels . ") ";
349
+
350
+ $sales = $wpdb->get_var($sqlQuery);
351
+
352
+ //save in cache
353
+ if(!empty($cache) && !empty($cache[$period]))
354
+ $cache[$period][$levels] = $sales;
355
+ elseif(!empty($cache))
356
+ $cache[$period] = array($levels => $sales);
357
+ else
358
+ $cache = array($period => array($levels => $sales));
359
+
360
+ set_transient("pmpro_report_sales", $cache, 3600*24);
361
+
362
+ return $sales;
363
+ }
364
+
365
+ //get revenue
366
+ function pmpro_getRevenue($period, $levels = NULL)
367
+ {
368
+ //check for a transient
369
+ $cache = get_transient("pmpro_report_revenue");
370
+ if(!empty($cache) && !empty($cache[$period]) && !empty($cache[$period][$levels]))
371
+ return $cache[$period][$levels];
372
+
373
+ //a sale is an order with status NOT IN('refunded', 'review', 'token', 'error')
374
+ if($period == "today")
375
+ $startdate = date("Y-m-d", current_time('timestamp'));
376
+ elseif($period == "this month")
377
+ $startdate = date("Y-m", current_time('timestamp')) . "-01";
378
+ elseif($period == "this year")
379
+ $startdate = date("Y", current_time('timestamp')) . "-01-01";
380
+ else
381
+ $startdate = "";
382
+
383
+ $gateway_environment = pmpro_getOption("gateway_environment");
384
+
385
+ //build query
386
+ global $wpdb;
387
+ $sqlQuery = "SELECT SUM(total) FROM $wpdb->pmpro_membership_orders WHERE status NOT IN('refunded', 'review', 'token', 'error') AND timestamp >= '" . $startdate . "' AND gateway_environment = '" . esc_sql($gateway_environment) . "' ";
388
+
389
+ //restrict by level
390
+ if(!empty($levels))
391
+ $sqlQuery .= "AND membership_id IN(" . $levels . ") ";
392
+
393
+ $revenue = $wpdb->get_var($sqlQuery);
394
+
395
+ //save in cache
396
+ if(!empty($cache) && !empty($cache[$period]))
397
+ $cache[$period][$levels] = $revenue;
398
+ elseif(!empty($cache))
399
+ $cache[$period] = array($levels => $revenue);
400
+ else
401
+ $cache = array($period => array($levels => $revenue));
402
+
403
+ set_transient("pmpro_report_revenue", $cache, 3600*24);
404
+
405
+ return $revenue;
406
+ }
407
+
408
+ //delete transients when an order goes through
409
+ function pmpro_report_sales_delete_transients()
410
+ {
411
+ delete_transient("pmpro_report_sales");
412
+ delete_transient("pmpro_report_revenue");
413
+ }
414
+ add_action("pmpro_after_checkout", "pmpro_report_sales_delete_transients");
415
+ add_action("pmpro_updated_order", "pmpro_report_sales_delete_transients");
adminpages/templates/orders-email.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Template for Email Invoices
4
+ *
5
+ * @since 1.8.6
6
+ */
7
+ ?>
8
+ <table style="width:600px;margin-left:auto;margin-right:auto;">
9
+ <thead>
10
+ <tr>
11
+ <td rowspan="2" style="width:80%;">
12
+ <h2><?php bloginfo( 'sitename' ); ?></h2>
13
+ </td>
14
+ <td><?php echo __('Invoice #: ', 'pmpro') . '&nbsp;' . $order->code; ?></td>
15
+ </tr>
16
+ <tr>
17
+ <td>
18
+ <?php echo __( 'Date:', 'pmpro' ) . '&nbsp;' . date( 'Y-m-d', $order->timestamp ) ?>
19
+ </td>
20
+ </tr>
21
+ <?php if(!empty($order->billing->name)): ?>
22
+ <tr>
23
+ <td>
24
+ <strong><?php _e( 'Bill to:', 'pmpro' ); ?></strong><br>
25
+ <?php
26
+ echo pmpro_formatAddress(
27
+ $order->billing->name,
28
+ $order->billing->street,
29
+ "",
30
+ $order->billing->city,
31
+ $order->billing->state,
32
+ $order->billing->zip,
33
+ $order->billing->country,
34
+ $order->billing->phone
35
+ );
36
+ ?>
37
+ <?php endif; ?>
38
+ </td>
39
+ </tr>
40
+ </thead>
41
+ <tbody>
42
+ <tr>
43
+ <td colspan="2">
44
+ <table style="width:100%;border-width:1px;border-style:solid;border-collapse:collapse;">
45
+ <tr style="border-width:1px;border-style:solid;border-collapse:collapse;">
46
+ <th style="text-align:center;border-width:1px;border-style:solid;border-collapse:collapse;"><?php _e('ID', 'pmpro'); ?></th>
47
+ <th style="border-width:1px;border-style:solid;border-collapse:collapse;"><?php _e('Item', 'pmpro'); ?></th>
48
+ <th style="border-width:1px;border-style:solid;border-collapse:collapse;"><?php _e('Price', 'pmpro'); ?></th>
49
+ </tr>
50
+ <tr style="border-width:1px;border-style:solid;border-collapse:collapse;">
51
+ <td style="text-align:center;border-width:1px;border-style:solid;border-collapse:collapse;"><?php echo $level->id; ?></td>
52
+ <td style="border-width:1px;border-style:solid;border-collapse:collapse;"><?php echo $level->name; ?></td>
53
+ <td style="text-align:right;"><?php echo $order->subtotal; ?></td>
54
+ </tr>
55
+ <tr style="border-width:1px;border-style:solid;border-collapse:collapse;">
56
+ <th colspan="2" style="text-align:right;border-width:1px;border-style:solid;border-collapse:collapse;"><?php _e('Subtotal', 'pmpro'); ?></th>
57
+ <td style="text-align:right;border-width:1px;border-style:solid;border-collapse:collapse;"><?php echo $order->subtotal; ?></td>
58
+ </tr>
59
+ <tr style="border-width:1px;border-style:solid;border-collapse:collapse;">
60
+ <th colspan="2" style="text-align:right;border-width:1px;border-style:solid;border-collapse:collapse;"><?php _e('Tax', 'pmpro'); ?></th>
61
+ <td style="text-align:right;border-width:1px;border-style:solid;border-collapse:collapse;"><?php echo $order->tax; ?></td>
62
+ </tr>
63
+ <tr style="border-width:1px;border-style:solid;border-collapse:collapse;">
64
+ <th colspan="2" style="text-align:right;border-width:1px;border-style:solid;border-collapse:collapse;"><?php _e('Total', 'pmpro'); ?></th>
65
+ <th style="text-align:right;border-width:1px;border-style:solid;border-collapse:collapse;"><?php echo pmpro_formatPrice($order->total); ?></th>
66
+ </tr>
67
+ </table>
68
+ </td>
69
+ </tr>
70
+ </tbody>
71
+ </table>
adminpages/templates/orders-print.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Template for Print Invoices
4
+ *
5
+ * @since 1.8.6
6
+ */
7
+ ?>
8
+ <!doctype html>
9
+ <html lang="en">
10
+ <head>
11
+ <meta charset="UTF-8">
12
+ <style>
13
+ .main, .header {
14
+ display: block;
15
+ }
16
+ .right {
17
+ display: inline-block;
18
+ float: right;
19
+ }
20
+ .alignright {
21
+ text-align: right;
22
+ }
23
+ .aligncenter {
24
+ text-align: center;
25
+ }
26
+ .invoice, .invoice tr, .invoice th, .invoice td {
27
+ border: 1px solid;
28
+ border-collapse: collapse;
29
+ padding: 4px;
30
+ }
31
+ .invoice {
32
+ width: 100%;
33
+ }
34
+ @media screen {
35
+ body {
36
+ max-width: 50%;
37
+ margin: 0 auto;
38
+ }
39
+ }
40
+ </style>
41
+ </head>
42
+ <body>
43
+ <header class="header">
44
+ <div>
45
+ <h2><?php bloginfo( 'sitename' ); ?></h2>
46
+ </div>
47
+ <div class="right">
48
+ <table>
49
+ <tr>
50
+ <td><?php echo __('Invoice #: ', 'pmpro') . '&nbsp;' . $order->code; ?></td>
51
+ </tr>
52
+ <tr>
53
+ <td>
54
+ <?php echo __( 'Date:', 'pmpro' ) . '&nbsp;' . date( 'Y-m-d', $order->timestamp ) ?>
55
+ </td>
56
+ </tr>
57
+ </table>
58
+ </div>
59
+ </header>
60
+ <main class="main">
61
+ <p>
62
+ <?php echo pmpro_formatAddress(
63
+ $order->billing->name,
64
+ $order->billing->address1,
65
+ $order->billing->address2,
66
+ $order->billing->city,
67
+ $order->billing->state,
68
+ $order->billing->zip,
69
+ $order->billing->country,
70
+ $order->billing->phone
71
+ ); ?>
72
+ </p>
73
+ <table class="invoice">
74
+ <tr>
75
+ <th><?php _e('ID', 'pmpro'); ?></th>
76
+ <th><?php _e('Item', 'pmpro'); ?></th>
77
+ <th><?php _e('Price', 'pmpro'); ?></th>
78
+ </tr>
79
+ <tr>
80
+ <td class="aligncenter"><?php echo $level->id; ?></td>
81
+ <td><?php echo $level->name; ?></td>
82
+ <td class="alignright"><?php echo $order->subtotal; ?></td>
83
+ </tr>
84
+ <tr>
85
+ <th colspan="2" class="alignright"><?php _e('Subtotal', 'pmpro'); ?></th>
86
+ <td class="alignright"><?php echo $order->subtotal; ?></td>
87
+ </tr>
88
+ <tr>
89
+ <th colspan="2" class="alignright"><?php _e('Tax', 'pmpro'); ?></th>
90
+ <td class="alignright"><?php echo $order->tax; ?></td>
91
+ </tr>
92
+ <tr>
93
+ <th colspan="2" class="alignright"><?php _e('Total', 'pmpro'); ?></th>
94
+ <th class="alignright"><?php echo pmpro_formatPrice( $order->total ); ?></th>
95
+ </tr>
96
+ </table>
97
+ </main>
98
+ </body>
99
+ </html>
classes/class.pmproemail.php CHANGED
@@ -821,4 +821,55 @@
821
 
822
  return $this->sendEmail();
823
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
824
  }
821
 
822
  return $this->sendEmail();
823
  }
824
+
825
+ /**
826
+ * Send billable invoice email.
827
+ *
828
+ * @since 1.8.6
829
+ *
830
+ * @param WP_User $user
831
+ * @param MemberOrder $order
832
+ *
833
+ * @return bool Whether the email was sent successfully.
834
+ */
835
+ function sendBillableInvoiceEmail($user = NULL, $order = NULL)
836
+ {
837
+ global $current_user;
838
+
839
+ if(!$user)
840
+ $user = $current_user;
841
+
842
+ if(!$user || !$order)
843
+ return false;
844
+
845
+ $level = pmpro_getLevel($order->membership_id);
846
+
847
+ $this->email = $user->user_email;
848
+ $this->subject = __('Invoice for Order #: ', 'pmpro') . $order->code;
849
+ $this->template = "billable_invoice";
850
+
851
+ // Load invoice template
852
+ if ( file_exists( get_stylesheet_directory() . '/paid-memberships-pro/pages/orders-email.php' ) ) {
853
+ $template = get_stylesheet_directory() . '/paid-memberships-pro/pages/orders-email.php';
854
+ } elseif ( file_exists( get_template_directory() . '/paid-memberships-pro/pages/orders-email.php' ) ) {
855
+ $template = get_template_directory() . '/paid-memberships-pro/pages/orders-email.php';
856
+ } else {
857
+ $template = PMPRO_DIR . '/adminpages/templates/orders-email.php';
858
+ }
859
+
860
+ ob_start();
861
+ require_once( $template );
862
+
863
+ $invoice = ob_get_contents();
864
+ ob_end_clean();
865
+
866
+ $this->data = array(
867
+ 'order_code' => $order->code,
868
+ 'login_link' => wp_login_url(pmpro_url("account")),
869
+ 'invoice_link' => wp_login_url(pmpro_url("invoice", "?invoice=" . $order->code)),
870
+ 'invoice' => $invoice
871
+ );
872
+
873
+ return $this->sendEmail();
874
+ }
875
  }
classes/gateways/class.pmprogateway_payflowpro.php CHANGED
@@ -242,6 +242,13 @@
242
  $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&BILLTOCOUNTRY=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&PHONENUM=" . $order->billing->phone;
243
  }
244
 
 
 
 
 
 
 
 
245
  //for debugging, let's attach this to the class object
246
  $this->nvpStr = $nvpStr;
247
 
@@ -268,6 +275,13 @@
268
  //paypal profile stuff
269
  $nvpStr="&ORIGID=" . $authorization_id;
270
 
 
 
 
 
 
 
 
271
  $this->httpParsedResponseAr = $this->PPHttpPost('V', $nvpStr);
272
 
273
  if("0" == strtoupper($this->httpParsedResponseAr["RESULT"])) {
@@ -316,6 +330,13 @@
316
  $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&BILLTOCOUNTRY=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&PHONENUM=" . $order->billing->phone;
317
  }
318
 
 
 
 
 
 
 
 
319
  $this->nvpStr = $nvpStr;
320
  $this->httpParsedResponseAr = $this->PPHttpPost('S', $nvpStr);
321
 
@@ -432,6 +453,13 @@
432
  $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&BILLTOCOUNTRY=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&PHONENUM=" . $order->billing->phone;
433
  }
434
 
 
 
 
 
 
 
 
435
  $this->nvpStr = $nvpStr;
436
  $this->httpParsedResponseAr = $this->PPHttpPost('R', $nvpStr);
437
 
@@ -474,6 +502,13 @@
474
  $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&BILLTOCOUNTRY=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&PHONENUM=" . $order->billing->phone;
475
  }
476
 
 
 
 
 
 
 
 
477
  $this->nvpStr = $nvpStr;
478
  $this->httpParsedResponseAr = $this->PPHttpPost('R', $nvpStr);
479
 
@@ -499,6 +534,13 @@
499
  //paypal profile stuff
500
  $nvpStr = "&ORIGPROFILEID=" . $order->subscription_transaction_id . "&ACTION=C";
501
 
 
 
 
 
 
 
 
502
  $this->nvpStr = $nvpStr;
503
  $this->httpParsedResponseAr = $this->PPHttpPost('R', $nvpStr);
504
 
242
  $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&BILLTOCOUNTRY=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&PHONENUM=" . $order->billing->phone;
243
  }
244
 
245
+ /**
246
+ * Filter NVP string
247
+ *
248
+ * @since 1.8.5.6
249
+ */
250
+ $nvpStr = apply_filters('pmpro_payflow_authorize_nvpstr', $nvpStr, $this);
251
+
252
  //for debugging, let's attach this to the class object
253
  $this->nvpStr = $nvpStr;
254
 
275
  //paypal profile stuff
276
  $nvpStr="&ORIGID=" . $authorization_id;
277
 
278
+ /**
279
+ * Filter NVP string
280
+ *
281
+ * @since 1.8.5.6
282
+ */
283
+ $nvpStr = apply_filters('pmpro_payflow_void_nvpstr', $nvpStr, $this);
284
+
285
  $this->httpParsedResponseAr = $this->PPHttpPost('V', $nvpStr);
286
 
287
  if("0" == strtoupper($this->httpParsedResponseAr["RESULT"])) {
330
  $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&BILLTOCOUNTRY=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&PHONENUM=" . $order->billing->phone;
331
  }
332
 
333
+ /**
334
+ * Filter NVP string
335
+ *
336
+ * @since 1.8.5.6
337
+ */
338
+ $nvpStr = apply_filters('pmpro_payflow_charge_nvpstr', $nvpStr, $this);
339
+
340
  $this->nvpStr = $nvpStr;
341
  $this->httpParsedResponseAr = $this->PPHttpPost('S', $nvpStr);
342
 
453
  $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&BILLTOCOUNTRY=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&PHONENUM=" . $order->billing->phone;
454
  }
455
 
456
+ /**
457
+ * Filter NVP string
458
+ *
459
+ * @since 1.8.5.6
460
+ */
461
+ $nvpStr = apply_filters('pmpro_payflow_subscribe_nvpstr', $nvpStr, $this);
462
+
463
  $this->nvpStr = $nvpStr;
464
  $this->httpParsedResponseAr = $this->PPHttpPost('R', $nvpStr);
465
 
502
  $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&BILLTOCOUNTRY=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&PHONENUM=" . $order->billing->phone;
503
  }
504
 
505
+ /**
506
+ * Filter NVP string
507
+ *
508
+ * @since 1.8.5.6
509
+ */
510
+ $nvpStr = apply_filters('pmpro_payflow_update_nvpstr', $nvpStr, $this);
511
+
512
  $this->nvpStr = $nvpStr;
513
  $this->httpParsedResponseAr = $this->PPHttpPost('R', $nvpStr);
514
 
534
  //paypal profile stuff
535
  $nvpStr = "&ORIGPROFILEID=" . $order->subscription_transaction_id . "&ACTION=C";
536
 
537
+ /**
538
+ * Filter NVP string
539
+ *
540
+ * @since 1.8.5.6
541
+ */
542
+ $nvpStr = apply_filters('pmpro_payflow_cancel_nvpstr', $nvpStr, $this);
543
+
544
  $this->nvpStr = $nvpStr;
545
  $this->httpParsedResponseAr = $this->PPHttpPost('R', $nvpStr);
546
 
classes/gateways/class.pmprogateway_stripe.php CHANGED
@@ -231,8 +231,7 @@
231
  {
232
  //build array for creating token
233
  var args = {
234
- number: jQuery('#AccountNumber').val(),
235
- cvc: jQuery('#CVV').val(),
236
  exp_month: jQuery('#ExpirationMonth').val(),
237
  exp_year: jQuery('#ExpirationYear').val()
238
  <?php
@@ -251,6 +250,11 @@
251
  ?>
252
  };
253
 
 
 
 
 
 
254
  if (jQuery('#bfirstname').length && jQuery('#blastname').length)
255
  args['name'] = jQuery.trim(jQuery('#bfirstname').val() + ' ' + jQuery('#blastname').val());
256
 
@@ -283,7 +287,7 @@
283
  // insert the token into the form so it gets submitted to the server
284
  form$.append("<input type='hidden' name='stripeToken' value='" + token + "'/>");
285
 
286
- console.log(response);
287
 
288
  //insert fields for other card fields
289
  if(jQuery('#CardType[name=CardType]').length)
@@ -1268,7 +1272,7 @@
1268
  }
1269
  catch (Exception $e)
1270
  {
1271
- $order->error = __("Error creating plan with Stripe:", "pmpro") . $e->getMessage();
1272
  $order->shorterror = $order->error;
1273
  return false;
1274
  }
231
  {
232
  //build array for creating token
233
  var args = {
234
+ number: jQuery('#AccountNumber').val(),
 
235
  exp_month: jQuery('#ExpirationMonth').val(),
236
  exp_year: jQuery('#ExpirationYear').val()
237
  <?php
250
  ?>
251
  };
252
 
253
+ //add CVC if not blank
254
+ if(jQuery('#CVV').val().length)
255
+ args['cvc'] = jQuery('#CVV').val();
256
+
257
+ //add first and last name if not blank
258
  if (jQuery('#bfirstname').length && jQuery('#blastname').length)
259
  args['name'] = jQuery.trim(jQuery('#bfirstname').val() + ' ' + jQuery('#blastname').val());
260
 
287
  // insert the token into the form so it gets submitted to the server
288
  form$.append("<input type='hidden' name='stripeToken' value='" + token + "'/>");
289
 
290
+ //console.log(response);
291
 
292
  //insert fields for other card fields
293
  if(jQuery('#CardType[name=CardType]').length)
1272
  }
1273
  catch (Exception $e)
1274
  {
1275
+ $order->error = __("Error getting subscription with Stripe:", "pmpro") . $e->getMessage();
1276
  $order->shorterror = $order->error;
1277
  return false;
1278
  }
css/admin.css CHANGED
@@ -1,118 +1,122 @@
1
- /* icon */
2
- #wp-admin-bar-paid-memberships-pro .ab-item .ab-icon:before {
3
- font-family: "dashicons";
4
- content: "\f307";
5
- }
6
- .pmpro_admin tr td .dashicons {padding-top: 5px; }
7
-
8
- /* header/etc */
9
- .pmpro_admin {background: url(../images/Paid-Memberships-Pro_watermark.png) bottom right no-repeat !important; padding: 1em 0 70px 0; }
10
-
11
- .pmpro_admin .pmpro_banner h2 {float: left; }
12
- .pmpro_admin .pmpro_banner .pmpro_meta {float: left; margin: 26px 0 0 0; font-size: 12px; }
13
- .pmpro_admin .pmpro_banner .pmpro_meta .pmpro_tag-blue {margin: 0 0 0 5px; }
14
- .pmpro_admin .pmpro_banner .pmpro_logo {float: left; margin: 0 1em 0 0; width: 350px; height: 75px; }
15
- .pmpro_admin .pmpro_banner ul.pmpro_menu {clear: both; border: 1px solid #CCC; border-radius: 5px; -moz-border-radius: 5px; background: #FFF; }
16
- .pmpro_admin .pmpro_banner ul.pmpro_menu li {display: inline-block; margin: 10px 0; padding: 0px 10px; border-right: 1px solid #CCC; }
17
- .pmpro_admin .pmpro_banner ul.pmpro_menu li a, .pmpro_admin .pmpro_banner ul.pmpro_menu li a:link {color: #1e0741; text-decoration: none; }
18
- .pmpro_admin .pmpro_banner ul.pmpro_menu li a:hover {text-decoration: underline; color: #412f5b; }
19
-
20
- .pmpro_admin .pmpro_tag-grey {display: inline-block; font-size: 11px; font-weight: bold; position: relative; padding: 2px 5px; border: 1px solid #CCC; background: whiteSmoke; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; }
21
- .pmpro_admin .pmpro_tag-blue {display: inline-block; font-size: 11px; font-weight: bold; position: relative; padding: 2px 5px; border: 1px solid #2997c8; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; background: #2997c8; color: #FFF; text-decoration: none; }
22
- .pmpro_admin a.pmpro_tag-blue:hover {background: #77a02e; border: 1px solid #77a02e; }
23
-
24
- .pmpro_admin .topborder {border-top: 1px solid #CCC; margin-top: 1em; padding-top: 1em; }
25
- .pmpro_admin #editorcontainer #description {width: 100%; height: 180px; }
26
- .pmpro_admin .widefat {margin-top: 1em; }
27
-
28
- /* checkboxes */
29
- .checkbox_box {width: 300px; background: #FFFFFF; border: 1px solid #CCC;}
30
- .checkbox_box div {border-bottom: 1px solid #CCC; padding: 3px;}
31
- .checkbox_box .clickable {cursor: pointer;}
32
- .checkbox_box .clickable:hover {background: #FFC;}
33
-
34
- /* levels */
35
- tr.pmpro_gray td {color: #AAA;}
36
- tr td.level_name a {font-size: 115%; font-weight: bold; }
37
- .membership-levels tr {background: #fff;}
38
- .membership-levels tr.alternate {background: #f9f9f9;}
39
- .membership-levels tr.ui-sortable-helper {border: 1px solid #2997C8;}
40
- tr.testclass {border: 3px solid #2997C8; background: #2997C8;}
41
-
42
- /* settings */
43
- tr.pmpro_settings_divider td {padding: 5px; margin: 0; color: #555; border-top: 1px solid #CCC; border-bottom: 1px solid #CCC;}
44
- tr.pmpro_settings_divider td:before {content: "- ";}
45
- tr.pmpro_settings_divider td:after {content: " -";}
46
-
47
- /* messages */
48
- .pmpro_message {background-color: #D5E4F7; background-image: url(../images/icon_information.gif); background-position: 3px 5px; background-repeat: no-repeat; margin: .5em 0; padding: 6px 6px 6px 25px; color: #345395; font-size: 11px; font-weight: bold; line-height: 1.3em; }
49
-
50
- .pmpro_success {background-color: #CFEECA; background-image: url(../images/icon_success.gif); color: #208A1B; }
51
- .pmpro_error {background-color: #F9D6CB; background-image: url(../images/icon_error.gif); color: #E36154; }
52
- .pmpro_alert {background-color: #FFF6CC; background-image: url(../images/icon_alert.gif); color: #CF8516; }
53
-
54
- .pmpro_message a {color: #345395; }
55
- .pmpro_success a {color: #208A1B; }
56
- .pmpro_error a {color: #E36154; }
57
- .pmpro_alert a {color: #CF8516; }
58
-
59
- /* highlighted trs */
60
- tr.pmpro_message {background-image: none;}
61
- tr.pmpro_success {background-image: none;}
62
- tr.pmpro_error {background-image: none;}
63
- tr.pmpro_alert {background-image: none;}
64
-
65
- /* discount levels */
66
- .pmpro_discount_levels {border: 1px solid #CCC;}
67
- .pmpro_discount_levels div {padding: 5px; border: 1px solid #CCC;}
68
- .pmpro_discount_levels div div {margin-top: 5px; background: #F5F5F5;}
69
-
70
- /* pagination */
71
- div.pmpro_pagination {padding: 3px; margin: 5px 0px 5px 0px; font-size: 10px; float: right; }
72
- div.pmpro_pagination a {padding: 2px 5px 2px 5px; margin: 1px; border: 1px solid #666; text-decoration: none; /* no underline */ color: #666; background: #EEE; }
73
- div.pmpro_pagination a:hover, div.pmpro_pagination a:active {background: #FFF; }
74
- div.pmpro_pagination span.current {border: 1px solid #FFF; color: #FFF; background: #666; padding: 2px 5px 2px 5px; margin: 1px; font-weight: bold; }
75
- div.pmpro_pagination span.disabled {padding: 2px 5px 2px 5px; margin: 2px; border: 1px solid #BBB; color: #BBB; background: #EFEFEF;}
76
-
77
- p.pmpro_meta_notice {font-size: .8em; padding-top: 5px; border-top: 1px solid #CCC;}
78
-
79
- /* add ons */
80
- .pmpro_admin .widgets-holder-wrap {clear: both; margin-top: 20px; padding: 0 8px; }
81
- .pmpro_admin .widgets-holder-wrap .widget {float: left; width: 32%; margin: 0 1% 1% 0; position: relative; }
82
- .pmpro_admin .widgets-holder-wrap p.description {padding: 0; }
83
- .pmpro_admin .widgets-holder-wrap .widget-top {height: auto; cursor: default; }
84
- .pmpro_admin .widgets-holder-wrap .widget-inside {display: block; height: 130px; overflow: hidden; }
85
- .pmpro_admin .widgets-holder-wrap .widget-inside p {height: 80px; overflow: hidden; }
86
- .pmpro_admin #pmpro-gists.widgets-holder-wrap .widget-inside, .pmpro_admin #pmpro-gists.widgets-holder-wrap .widget-inside p {height: auto; }
87
- .pmpro_admin .widgets-holder-wrap .widget-title { }
88
- .pmpro_admin .widgets-holder-wrap .widget-title h4 { }
89
- .pmpro_admin .widgets-holder-wrap .widget-title .status-label {display: block; float: left; margin: 0 5px 0 0; width: 10px;
90
- height: 10px; overflow: hidden; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; border: 1px solid #DFDFDF; text-indent: -9999em; }
91
- .pmpro_admin .widgets-holder-wrap .disabled .widget-title .status-label {background: #F00; }
92
- .pmpro_admin .widgets-holder-wrap .enabled .widget-title .status-label {background: #0C0; }
93
-
94
- .pmpro_admin .widgets-holder-wrap .widget-title .version {position: absolute; top: 13px; right: 10px; }
95
- .pmpro_admin .widgets-holder-wrap .widget-inside .addon-thumb {width: 100px; height: 100px; float: right; margin: 10px 0 0 10px; border: 1px solid #DFDFDF; background: #FFF; padding: 2px;}
96
-
97
- /*@media (min-width: 1200px) {
98
- .auto-fold .pmpro_admin .widgets-holder-wrap .widget-inside, .auto-fold .pmpro_admin .widgets-holder-wrap .widget-inside p {height: auto; }
99
- }
100
- */
101
- @media (max-width:900px) {
102
- .auto-fold .pmpro_admin .widgets-holder-wrap .widget {float: none; width: 100%; }
103
- .auto-fold .pmpro_admin .widgets-holder-wrap .widget-inside, .auto-fold .pmpro_admin .widgets-holder-wrap .widget-inside p {height: auto; }
104
- }
105
-
106
- /* misc */
107
- .pmpro_lite {color: #AAA;}
108
- .pmpro_pad20 {padding: 20px !important;}
109
- .pmpro_red {color: #CC0000;}
110
- .pmpro_green {color: #00AA00;}
111
- .ssp_description #description {width: 100%;}
112
- .top0em {margin-top: 0;}
113
- h2.nav-tab-wrapper {margin-bottom: 1em; }
114
-
115
- /* reports */
116
- .pmpro_reports-holder { }
117
- .pmpro_clickable {cursor: pointer;}
118
- .js .postbox.pmpro_clickable h3 {cursor: pointer;}
 
 
 
 
1
+ /* icon */
2
+ #wp-admin-bar-paid-memberships-pro .ab-item .ab-icon:before {
3
+ font-family: "dashicons";
4
+ content: "\f307";
5
+ }
6
+ .pmpro_admin tr td .dashicons {padding-top: 5px; }
7
+
8
+ /* header/etc */
9
+ .pmpro_admin {background: url(../images/Paid-Memberships-Pro_watermark.png) bottom right no-repeat !important; padding: 1em 0 70px 0; }
10
+
11
+ .pmpro_admin .pmpro_banner h2 {float: left; }
12
+ .pmpro_admin .pmpro_banner .pmpro_meta {float: left; margin: 26px 0 0 0; font-size: 12px; }
13
+ .pmpro_admin .pmpro_banner .pmpro_meta .pmpro_tag-blue {margin: 0 0 0 5px; }
14
+ .pmpro_admin .pmpro_banner .pmpro_logo {float: left; margin: 0 1em 0 0; width: 350px; height: 75px; }
15
+ .pmpro_admin .pmpro_banner ul.pmpro_menu {clear: both; border: 1px solid #CCC; border-radius: 5px; -moz-border-radius: 5px; background: #FFF; }
16
+ .pmpro_admin .pmpro_banner ul.pmpro_menu li {display: inline-block; margin: 10px 0; padding: 0px 10px; border-right: 1px solid #CCC; }
17
+ .pmpro_admin .pmpro_banner ul.pmpro_menu li a, .pmpro_admin .pmpro_banner ul.pmpro_menu li a:link {color: #1e0741; text-decoration: none; }
18
+ .pmpro_admin .pmpro_banner ul.pmpro_menu li a:hover {text-decoration: underline; color: #412f5b; }
19
+
20
+ .pmpro_admin .pmpro_tag-grey {display: inline-block; font-size: 11px; font-weight: bold; position: relative; padding: 2px 5px; border: 1px solid #CCC; background: whiteSmoke; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; }
21
+ .pmpro_admin .pmpro_tag-blue {display: inline-block; font-size: 11px; font-weight: bold; position: relative; padding: 2px 5px; border: 1px solid #2997c8; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; background: #2997c8; color: #FFF; text-decoration: none; }
22
+ .pmpro_admin a.pmpro_tag-blue:hover {background: #77a02e; border: 1px solid #77a02e; }
23
+
24
+ .pmpro_admin .topborder {border-top: 1px solid #CCC; margin-top: 1em; padding-top: 1em; }
25
+ .pmpro_admin #editorcontainer #description {width: 100%; height: 180px; }
26
+ .pmpro_admin .widefat {margin-top: 1em; }
27
+
28
+ /* checkboxes */
29
+ .checkbox_box {width: 300px; background: #FFFFFF; border: 1px solid #CCC;}
30
+ .checkbox_box div {border-bottom: 1px solid #CCC; padding: 3px;}
31
+ .checkbox_box .clickable {cursor: pointer;}
32
+ .checkbox_box .clickable:hover {background: #FFC;}
33
+
34
+ /* levels */
35
+ tr.pmpro_gray td {color: #AAA;}
36
+ tr td.level_name a {font-size: 115%; font-weight: bold; }
37
+ .membership-levels tr {background: #fff;}
38
+ .membership-levels tr.alternate {background: #f9f9f9;}
39
+ .membership-levels tr.ui-sortable-helper {border: 1px solid #2997C8;}
40
+ tr.testclass {border: 3px solid #2997C8; background: #2997C8;}
41
+
42
+ /* settings */
43
+ tr.pmpro_settings_divider td {padding: 5px; margin: 0; color: #555; border-top: 1px solid #CCC; border-bottom: 1px solid #CCC;}
44
+ tr.pmpro_settings_divider td:before {content: "- ";}
45
+ tr.pmpro_settings_divider td:after {content: " -";}
46
+
47
+ /* messages */
48
+ .pmpro_message {background-color: #D5E4F7; background-image: url(../images/icon_information.gif); background-position: 3px 5px; background-repeat: no-repeat; margin: .5em 0; padding: 6px 6px 6px 25px; color: #345395; font-size: 11px; font-weight: bold; line-height: 1.3em; }
49
+
50
+ .pmpro_success {background-color: #CFEECA; background-image: url(../images/icon_success.gif); color: #208A1B; }
51
+ .pmpro_error {background-color: #F9D6CB; background-image: url(../images/icon_error.gif); color: #E36154; }
52
+ .pmpro_alert {background-color: #FFF6CC; background-image: url(../images/icon_alert.gif); color: #CF8516; }
53
+
54
+ .pmpro_message a {color: #345395; }
55
+ .pmpro_success a {color: #208A1B; }
56
+ .pmpro_error a {color: #E36154; }
57
+ .pmpro_alert a {color: #CF8516; }
58
+
59
+ /* highlighted trs */
60
+ tr.pmpro_message {background-image: none;}
61
+ tr.pmpro_success {background-image: none;}
62
+ tr.pmpro_error {background-image: none;}
63
+ tr.pmpro_alert {background-image: none;}
64
+
65
+ /* discount levels */
66
+ .pmpro_discount_levels {border: 1px solid #CCC;}
67
+ .pmpro_discount_levels div {padding: 5px; border: 1px solid #CCC;}
68
+ .pmpro_discount_levels div div {margin-top: 5px; background: #F5F5F5;}
69
+
70
+ /* pagination */
71
+ div.pmpro_pagination {padding: 3px; margin: 5px 0px 5px 0px; font-size: 10px; float: right; }
72
+ div.pmpro_pagination a {padding: 2px 5px 2px 5px; margin: 1px; border: 1px solid #666; text-decoration: none; /* no underline */ color: #666; background: #EEE; }
73
+ div.pmpro_pagination a:hover, div.pmpro_pagination a:active {background: #FFF; }
74
+ div.pmpro_pagination span.current {border: 1px solid #FFF; color: #FFF; background: #666; padding: 2px 5px 2px 5px; margin: 1px; font-weight: bold; }
75
+ div.pmpro_pagination span.disabled {padding: 2px 5px 2px 5px; margin: 2px; border: 1px solid #BBB; color: #BBB; background: #EFEFEF;}
76
+
77
+ p.pmpro_meta_notice {font-size: .8em; padding-top: 5px; border-top: 1px solid #CCC;}
78
+
79
+ /* add ons */
80
+ .pmpro_admin .widgets-holder-wrap {clear: both; margin-top: 20px; padding: 0 8px; }
81
+ .pmpro_admin .widgets-holder-wrap .widget {float: left; width: 32%; margin: 0 1% 1% 0; position: relative; }
82
+ .pmpro_admin .widgets-holder-wrap p.description {padding: 0; }
83
+ .pmpro_admin .widgets-holder-wrap .widget-top {height: auto; cursor: default; }
84
+ .pmpro_admin .widgets-holder-wrap .widget-inside {display: block; height: 130px; overflow: hidden; }
85
+ .pmpro_admin .widgets-holder-wrap .widget-inside p {height: 80px; overflow: hidden; }
86
+ .pmpro_admin #pmpro-gists.widgets-holder-wrap .widget-inside, .pmpro_admin #pmpro-gists.widgets-holder-wrap .widget-inside p {height: auto; }
87
+ .pmpro_admin .widgets-holder-wrap .widget-title { }
88
+ .pmpro_admin .widgets-holder-wrap .widget-title h4 { }
89
+ .pmpro_admin .widgets-holder-wrap .widget-title .status-label {display: block; float: left; margin: 0 5px 0 0; width: 10px;
90
+ height: 10px; overflow: hidden; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; border: 1px solid #DFDFDF; text-indent: -9999em; }
91
+ .pmpro_admin .widgets-holder-wrap .disabled .widget-title .status-label {background: #F00; }
92
+ .pmpro_admin .widgets-holder-wrap .enabled .widget-title .status-label {background: #0C0; }
93
+
94
+ .pmpro_admin .widgets-holder-wrap .widget-title .version {position: absolute; top: 13px; right: 10px; }
95
+ .pmpro_admin .widgets-holder-wrap .widget-inside .addon-thumb {width: 100px; height: 100px; float: right; margin: 10px 0 0 10px; border: 1px solid #DFDFDF; background: #FFF; padding: 2px;}
96
+
97
+ /*@media (min-width: 1200px) {
98
+ .auto-fold .pmpro_admin .widgets-holder-wrap .widget-inside, .auto-fold .pmpro_admin .widgets-holder-wrap .widget-inside p {height: auto; }
99
+ }
100
+ */
101
+ @media (max-width:900px) {
102
+ .auto-fold .pmpro_admin .widgets-holder-wrap .widget {float: none; width: 100%; }
103
+ .auto-fold .pmpro_admin .widgets-holder-wrap .widget-inside, .auto-fold .pmpro_admin .widgets-holder-wrap .widget-inside p {height: auto; }
104
+ }
105
+
106
+ /* misc */
107
+ .pmpro_lite {color: #AAA;}
108
+ .pmpro_pad20 {padding: 20px !important;}
109
+ .pmpro_red {color: #CC0000;}
110
+ .pmpro_green {color: #00AA00;}
111
+ .ssp_description #description {width: 100%;}
112
+ .top0em {margin-top: 0;}
113
+ h2.nav-tab-wrapper {margin-bottom: 1em; }
114
+
115
+ /* reports */
116
+ .pmpro_reports-holder { }
117
+ .pmpro_clickable {cursor: pointer;}
118
+ .js .postbox.pmpro_clickable h3 {cursor: pointer;}
119
+ .pmpro_reports-holder .wp-list-table tbody td {font-size: 1.2rem; font-weight: bold; }
120
+ @media screen and (max-width: 782px) {
121
+ .pmpro_reports-holder tr:not(.inline-edit-row):not(.no-items) td:not(.check-column) {display: table-cell; }
122
+ }
css/frontend.css CHANGED
@@ -177,9 +177,6 @@ li.pmpro_more {list-style-type: none; text-align: center; margin-left: -20px; pa
177
 
178
  .pmpro_small {font-size: .8em;}
179
 
180
- /* Fixes for Twentyfiften and other themes. */
181
- #your-profile input {display: inline-block; width: auto; } /* front end profile via Theme My Login */
182
-
183
  @media (max-width:768px){
184
  #pmpro_levels_table {border: none; }
185
  #pmpro_levels_table th {display: none; }
177
 
178
  .pmpro_small {font-size: .8em;}
179
 
 
 
 
180
  @media (max-width:768px){
181
  #pmpro_levels_table {border: none; }
182
  #pmpro_levels_table th {display: none; }
email/billable_invoice.html ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <p>Thank you for your membership to !!sitename!!. Below is your invoice for order #: !!order_code!!</p>
2
+
3
+ !!invoice!!
4
+
5
+ <p>Log in to your membership account here: !!login_link!!</p>
6
+ <p>To view an online version of this invoice, click here: !!invoice_link!!</p>
includes/content.php CHANGED
@@ -323,7 +323,7 @@ function pmpro_membership_content_filter($content, $skipcheck = false)
323
  $pmpro_content_message_post = '</div>';
324
 
325
  $sr_search = array("!!levels!!", "!!referrer!!");
326
- $sr_replace = array(pmpro_implodeToEnglish($post_membership_levels_names), $_SERVER['REQUEST_URI']);
327
 
328
  //get the correct message to show at the bottom
329
  if(is_feed())
@@ -472,10 +472,16 @@ add_action('wp', 'pmpro_hide_pages_redirect');
472
  *
473
  * @since 1.8.5.4
474
  */
475
- function pmpro_post_classes( $classes ) {
476
- global $post;
 
 
 
 
 
477
  $post_levels = array();
478
  $post_levels = pmpro_has_membership_access($post->ID,NULL,true);
 
479
  if(!empty($post_levels))
480
  {
481
  if(!empty($post_levels[1]))
@@ -489,4 +495,42 @@ function pmpro_post_classes( $classes ) {
489
  }
490
  return $classes;
491
  }
492
- add_filter( 'post_class', 'pmpro_post_classes' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
  $pmpro_content_message_post = '</div>';
324
 
325
  $sr_search = array("!!levels!!", "!!referrer!!");
326
+ $sr_replace = array(pmpro_implodeToEnglish($post_membership_levels_names), site_url($_SERVER['REQUEST_URI']));
327
 
328
  //get the correct message to show at the bottom
329
  if(is_feed())
472
  *
473
  * @since 1.8.5.4
474
  */
475
+ function pmpro_post_classes( $classes, $class, $post_id ) {
476
+
477
+ $post = get_post($post_id);
478
+
479
+ if(empty($post))
480
+ return $classes;
481
+
482
  $post_levels = array();
483
  $post_levels = pmpro_has_membership_access($post->ID,NULL,true);
484
+
485
  if(!empty($post_levels))
486
  {
487
  if(!empty($post_levels[1]))
495
  }
496
  return $classes;
497
  }
498
+ add_filter( 'post_class', 'pmpro_post_classes', 10, 3 );
499
+
500
+ /**
501
+ * Adds custom classes to the array of body classes.
502
+ * Same as the above, but acts on the "queried object" instead of the post global.
503
+ *
504
+ * pmpro-body-level-required = this post requires at least one level
505
+ * pmpro-body-level-1 = this post requires level 1
506
+ * pmpro-body-has-access = this post is usually locked, but the current user has access to this post
507
+ *
508
+ * @param array $classes Classes for the body element.
509
+ * @return array
510
+ *
511
+ * @since 1.8.6.1
512
+ */
513
+ function pmpro_body_classes( $classes ) {
514
+
515
+ $post = get_queried_object();
516
+
517
+ if(empty($post))
518
+ return $classes;
519
+
520
+ $post_levels = array();
521
+ $post_levels = pmpro_has_membership_access($post->ID,NULL,true);
522
+
523
+ if(!empty($post_levels))
524
+ {
525
+ if(!empty($post_levels[1]))
526
+ {
527
+ $classes[] = 'pmpro-body-level-required';
528
+ foreach($post_levels[1] as $post_level)
529
+ $classes[] = 'pmpro-body-level-' . $post_level[0];
530
+ }
531
+ if(!empty($post_levels[0]) && $post_levels[0] == true)
532
+ $classes[] = 'pmpro-body-has-access';
533
+ }
534
+ return $classes;
535
+ }
536
+ add_filter( 'body_class', 'pmpro_body_classes' );
includes/currencies.php CHANGED
@@ -3,12 +3,22 @@
3
  global $pmpro_currencies, $pmpro_default_currency;
4
  $pmpro_default_currency = apply_filters("pmpro_default_currency", "USD");
5
 
 
 
 
 
 
 
 
 
 
 
6
  $pmpro_currencies = array(
7
  'USD' => __('US Dollars (&#36;)', 'pmpro'),
8
  'EUR' => array(
9
  'name' => __('Euros (&euro;)', 'pmpro'),
10
  'symbol' => '&euro;',
11
- 'position' => 'right'
12
  ),
13
  'GBP' => array(
14
  'name' => __('Pounds Sterling (&pound;)', 'pmpro'),
3
  global $pmpro_currencies, $pmpro_default_currency;
4
  $pmpro_default_currency = apply_filters("pmpro_default_currency", "USD");
5
 
6
+ function pmpro_euro_position_from_locale($position = 'right')
7
+ {
8
+ $locale = get_locale();
9
+ if(strpos($locale, 'en_') === 0)
10
+ {
11
+ $position = 'left';
12
+ }
13
+ return $position;
14
+ }
15
+
16
  $pmpro_currencies = array(
17
  'USD' => __('US Dollars (&#36;)', 'pmpro'),
18
  'EUR' => array(
19
  'name' => __('Euros (&euro;)', 'pmpro'),
20
  'symbol' => '&euro;',
21
+ 'position' => apply_filters("pmpro_euro_position", pmpro_euro_position_from_locale())
22
  ),
23
  'GBP' => array(
24
  'name' => __('Pounds Sterling (&pound;)', 'pmpro'),
includes/functions.php CHANGED
@@ -1,2061 +1,2116 @@
1
- <?php
2
- /****************************************************************
3
-
4
- IMPORTANT. PLEASE READ.
5
-
6
- DO NOT EDIT THIS FILE or any other file in the /wp-content/plugins/paid-memberships-pro/ directory.
7
- Doing so could break the PMPro plugin and/or keep you from upgrading this plugin in the future.
8
- We regularly release updates to the plugin, including important security fixes and new features.
9
- You want to be able to upgrade.
10
-
11
- If you were asked to insert code into "your functions.php file", it was meant that you edit the functions.php
12
- in the root folder of your active theme. e.g. /wp-content/themes/twentytwelve/functions.php
13
- You can also create a custom plugin to place customization code into. Instructions are here:
14
- http://www.paidmembershipspro.com/2012/08/create-a-plugin-for-pmpro-customizations/
15
-
16
- Further documentation for customizing Paid Memberships Pro can be found here:
17
- http://www.paidmembershipspro.com/documentation/
18
-
19
- ****************************************************************/
20
- if(!function_exists("sornot"))
21
- {
22
- function sornot($t, $n)
23
- {
24
- if($n == 1)
25
- return $t;
26
- else
27
- return $t . "s";
28
- }
29
- }
30
-
31
- //set up wpdb for the tables we need
32
- function pmpro_setDBTables()
33
- {
34
- global $wpdb;
35
- $wpdb->hide_errors();
36
- $wpdb->pmpro_membership_levels = $wpdb->prefix . 'pmpro_membership_levels';
37
- $wpdb->pmpro_memberships_users = $wpdb->prefix . 'pmpro_memberships_users';
38
- $wpdb->pmpro_memberships_categories = $wpdb->prefix . 'pmpro_memberships_categories';
39
- $wpdb->pmpro_memberships_pages = $wpdb->prefix . 'pmpro_memberships_pages';
40
- $wpdb->pmpro_membership_orders = $wpdb->prefix . 'pmpro_membership_orders';
41
- $wpdb->pmpro_discount_codes = $wpdb->prefix . 'pmpro_discount_codes';
42
- $wpdb->pmpro_discount_codes_levels = $wpdb->prefix . 'pmpro_discount_codes_levels';
43
- $wpdb->pmpro_discount_codes_uses = $wpdb->prefix . 'pmpro_discount_codes_uses';
44
- }
45
- pmpro_setDBTables();
46
-
47
- //from: http://stackoverflow.com/questions/5266945/wordpress-how-detect-if-current-page-is-the-login-page/5892694#5892694
48
- function pmpro_is_login_page() {
49
- return (in_array($GLOBALS['pagenow'], array('wp-login.php', 'wp-register.php')) || is_page("login"));
50
- }
51
-
52
- //thanks: http://wordpress.org/support/topic/is_plugin_active
53
- function pmpro_is_plugin_active( $plugin ) {
54
- return in_array( $plugin, (array) get_option( 'active_plugins', array() ) );
55
- }
56
-
57
- //scraping - override n if you have more than 1 group of matches and don't want the first group
58
- function pmpro_getMatches($p, $s, $firstvalue = FALSE, $n = 1)
59
- {
60
- $ok = preg_match_all($p, $s, $matches);
61
-
62
- if(!$ok)
63
- return false;
64
- else
65
- {
66
- if($firstvalue)
67
- return $matches[$n][0];
68
- else
69
- return $matches[$n];
70
- }
71
- }
72
-
73
- function pmpro_br2nl($text, $tags = "br")
74
- {
75
- if(!is_array($tags))
76
- $tags = explode(" ", $tags);
77
-
78
- foreach($tags as $tag)
79
- {
80
- $text = eregi_replace("<" . $tag . "[^>]*>", "\n", $text);
81
- $text = eregi_replace("</" . $tag . "[^>]*>", "\n", $text);
82
- }
83
-
84
- return($text);
85
- }
86
-
87
- function pmpro_getOption($s, $force = false)
88
- {
89
- if(get_option("pmpro_" . $s))
90
- return get_option("pmpro_" . $s);
91
- else
92
- return "";
93
- }
94
-
95
- function pmpro_setOption($s, $v = NULL)
96
- {
97
- //no value is given, set v to the p var
98
- if($v === NULL && isset($_POST[$s]))
99
- $v = $_POST[$s];
100
-
101
- if(is_array($v))
102
- $v = implode(",", $v);
103
- else
104
- $v = trim($v);
105
-
106
- return update_option("pmpro_" . $s, $v);
107
- }
108
-
109
- function pmpro_get_slug($post_id)
110
- {
111
- global $pmpro_slugs, $wpdb;
112
-
113
- //make sure post id is int for security
114
- $post_id = intval($post_id);
115
-
116
- if(!$pmpro_slugs[$post_id])
117
- $pmpro_slugs[$post_id] = $wpdb->get_var("SELECT post_name FROM $wpdb->posts WHERE ID = '" . $post_id . "' LIMIT 1");
118
-
119
- return $pmpro_slugs[$post_id];
120
- }
121
-
122
- function pmpro_url($page = NULL, $querystring = "", $scheme = NULL)
123
- {
124
- global $besecure;
125
- $besecure = apply_filters("besecure", $besecure);
126
-
127
- if(!$scheme && $besecure)
128
- $scheme = "https";
129
- elseif(!$scheme)
130
- $scheme = "http";
131
-
132
- if(!$page)
133
- $page = "levels";
134
-
135
- global $pmpro_pages;
136
-
137
- //start with the permalink
138
- $url = get_permalink($pmpro_pages[$page]);
139
-
140
- //WPML/etc support
141
- if(function_exists("icl_object_id") && defined("ICL_LANGUAGE_CODE"))
142
- {
143
- $trans_id = icl_object_id($pmpro_pages[$page], "page", false, ICL_LANGUAGE_CODE);
144
- if(!empty($trans_id))
145
- {
146
- $url = get_permalink($trans_id);
147
- }
148
- }
149
-
150
- //figure out querystring
151
- if(strpos($url, "?"))
152
- $querystring = str_replace("?", "&", $querystring);
153
- $url .= $querystring;
154
-
155
- //figure out scheme
156
- if(is_ssl())
157
- $url = str_replace("http:", "https:", $url);
158
-
159
- return $url;
160
- }
161
-
162
- function pmpro_isLevelFree(&$level)
163
- {
164
- if(!empty($level) && $level->initial_payment <= 0 && $level->billing_amount <= 0 && $level->trial_amount <= 0)
165
- return true;
166
- else
167
- return false;
168
- }
169
-
170
- function pmpro_isLevelRecurring(&$level)
171
- {
172
- if(!empty($level) && ($level->billing_amount > 0 || $level->trial_amount > 0))
173
- return true;
174
- else
175
- return false;
176
- }
177
-
178
- function pmpro_isLevelTrial(&$level)
179
- {
180
- if($level->trial_limit > 0)
181
- {
182
- return true;
183
- }
184
- else
185
- return false;
186
- }
187
-
188
- function pmpro_isLevelExpiring(&$level)
189
- {
190
- if($level->expiration_number > 0)
191
- return true;
192
- else
193
- return false;
194
- }
195
-
196
- function pmpro_getLevelCost(&$level, $tags = true, $short = false)
197
- {
198
- //initial payment
199
- if(!$short)
200
- $r = sprintf(__('The price for membership is <strong>%s</strong> now', 'pmpro'), pmpro_formatPrice($level->initial_payment));
201
- else
202
- $r = sprintf(__('<strong>%s</strong> now', 'pmpro'), pmpro_formatPrice($level->initial_payment));
203
-
204
- //recurring part
205
- if($level->billing_amount != '0.00')
206
- {
207
- if($level->billing_limit > 1)
208
- {
209
- if($level->cycle_number == '1')
210
- {
211
- $r .= sprintf(__(' and then <strong>%s per %s for %d more %s</strong>.', 'pmpro'), pmpro_formatPrice($level->billing_amount), pmpro_translate_billing_period($level->cycle_period), $level->billing_limit, pmpro_translate_billing_period($level->cycle_period, $level->billing_limit));
212
- }
213
- else
214
- {
215
- $r .= sprintf(__(' and then <strong>%s every %d %s for %d more %s</strong>.', 'pmpro'), pmpro_formatPrice($level->billing_amount), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number), $level->billing_limit, pmpro_translate_billing_period($level->cycle_period, $level->billing_limit));
216
- }
217
- }
218
- elseif($level->billing_limit == 1)
219
- {
220
- $r .= sprintf(__(' and then <strong>%s after %d %s</strong>.', 'pmpro'), pmpro_formatPrice($level->billing_amount), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number));
221
- }
222
- else
223
- {
224
- if( $level->billing_amount === $level->initial_payment ) {
225
- if($level->cycle_number == '1')
226
- {
227
- if(!$short)
228
- $r = sprintf(__('The price for membership is <strong>%s per %s</strong>.', 'pmpro'), pmpro_formatPrice($level->initial_payment), pmpro_translate_billing_period($level->cycle_period) );
229
- else
230
- $r = sprintf(__('<strong>%s per %s</strong>.', 'pmpro'), pmpro_formatPrice($level->initial_payment), pmpro_translate_billing_period($level->cycle_period) );
231
- }
232
- else
233
- {
234
- if(!$short)
235
- $r = sprintf(__('The price for membership is <strong>%s every %d %s</strong>.', 'pmpro'), pmpro_formatPrice($level->initial_payment), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number) );
236
- else
237
- $r = sprintf(__('<strong>%s every %d %s</strong>.', 'pmpro'), pmpro_formatPrice($level->initial_payment), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number) );
238
- }
239
- } else {
240
- if($level->cycle_number == '1')
241
- {
242
- $r .= sprintf(__(' and then <strong>%s per %s</strong>.', 'pmpro'), pmpro_formatPrice($level->billing_amount), pmpro_translate_billing_period($level->cycle_period));
243
- }
244
- else
245
- {
246
- $r .= sprintf(__(' and then <strong>%s every %d %s</strong>.', 'pmpro'), pmpro_formatPrice($level->billing_amount), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number));
247
- }
248
- }
249
- }
250
- }
251
- else
252
- $r .= '.';
253
-
254
- //add a space
255
- $r .= ' ';
256
-
257
- //trial part
258
- if($level->trial_limit)
259
- {
260
- if($level->trial_amount == '0.00')
261
- {
262
- if($level->trial_limit == '1')
263
- {
264
- $r .= ' ' . __('After your initial payment, your first payment is Free.', 'pmpro');
265
- }
266
- else
267
- {
268
- $r .= ' ' . sprintf(__('After your initial payment, your first %d payments are Free.', 'pmpro'), $level->trial_limit);
269
- }
270
- }
271
- else
272
- {
273
- if($level->trial_limit == '1')
274
- {
275
- $r .= ' ' . sprintf(__('After your initial payment, your first payment will cost %s.', 'pmpro'), pmpro_formatPrice($level->trial_amount));
276
- }
277
- else
278
- {
279
- $r .= ' ' . sprintf(__('After your initial payment, your first %d payments will cost %s.', 'pmpro'), $level->trial_limit, pmpro_formatPrice($level->trial_amount));
280
- }
281
- }
282
- }
283
-
284
- //taxes part
285
- $tax_state = pmpro_getOption("tax_state");
286
- $tax_rate = pmpro_getOption("tax_rate");
287
-
288
- if($tax_state && $tax_rate && !pmpro_isLevelFree($level))
289
- {
290
- $r .= sprintf(__('Customers in %s will be charged %s%% tax.', 'pmpro'), $tax_state, round($tax_rate * 100, 2));
291
- }
292
-
293
- if(!$tags)
294
- $r = strip_tags($r);
295
-
296
- $r = apply_filters("pmpro_level_cost_text", $r, $level, $tags, $short); //passing $tags and $short since v2.0
297
- return $r;
298
- }
299
-
300
- function pmpro_getLevelExpiration(&$level)
301
- {
302
- if($level->expiration_number)
303
- {
304
- $expiration_text = sprintf(__("Membership expires after %d %s.", "pmpro"), $level->expiration_number, pmpro_translate_billing_period($level->expiration_period, $level->expiration_number));
305
- }
306
- else
307
- $expiration_text = "";
308
-
309
- $expiration_text = apply_filters("pmpro_level_expiration_text", $expiration_text, $level);
310
- return $expiration_text;
311
- }
312
-
313
- function pmpro_hideAds()
314
- {
315
- global $pmpro_display_ads;
316
- return !$pmpro_display_ads;
317
- }
318
-
319
- function pmpro_displayAds()
320
- {
321
- global $pmpro_display_ads;
322
- return $pmpro_display_ads;
323
- }
324
-
325
- function pmpro_next_payment($user_id = NULL, $order_status = "success", $format = "timestamp")
326
- {
327
- global $wpdb, $current_user;
328
- if(!$user_id)
329
- $user_id = $current_user->ID;
330
-
331
- if(!$user_id)
332
- $r = false;
333
- else
334
- {
335
- //get last order
336
- $order = new MemberOrder();
337
- $order->getLastMemberOrder($user_id, $order_status);
338
-
339
- //get current membership level
340
- $level = pmpro_getMembershipLevelForUser($user_id);
341
-
342
- if(!empty($order) && !empty($order->id) && !empty($level) && !empty($level->id) && !empty($level->cycle_number))
343
- {
344
- //last payment date
345
- $lastdate = date("Y-m-d", $order->timestamp);
346
-
347
- //next payment date
348
- $nextdate = $wpdb->get_var("SELECT UNIX_TIMESTAMP('" . $lastdate . "' + INTERVAL " . $level->cycle_number . " " . $level->cycle_period . ")");
349
-
350
- $r = $nextdate;
351
- }
352
- else
353
- {
354
- //no order or level found, or level was not recurring
355
- $r = false;
356
- }
357
- }
358
-
359
- /**
360
- * Filter the next payment date.
361
- *
362
- * @since 1.8.5
363
- *
364
- * @param mixed $r false or the next payment date timestamp
365
- * @param int $user_id The user id to get the next payment date for
366
- * @param string $order_status Status or array of statuses to find the last order based on.
367
- */
368
- $r = apply_filters('pmpro_next_payment', $r, $user_id, $order_status);
369
-
370
- //return in desired format
371
- if($r === false)
372
- return false; //always return false when no date found
373
- elseif($format == "timestamp")
374
- return $r;
375
- elseif($format == "date_format")
376
- return date(get_option('date_format'), $r);
377
- else
378
- return date($format, $r); //assume a PHP date format
379
- }
380
-
381
- if(!function_exists("last4"))
382
- {
383
- function last4($t)
384
- {
385
- return substr($t, strlen($t) - 4, 4);
386
- }
387
- }
388
-
389
- if(!function_exists("hideCardNumber"))
390
- {
391
- function hideCardNumber($c, $dashes = true)
392
- {
393
- if($c)
394
- {
395
- if($dashes)
396
- return "XXXX-XXXX-XXXX-" . substr($c, strlen($c) - 4, 4);
397
- else
398
- return "XXXXXXXXXXXX" . substr($c, strlen($c) - 4, 4);
399
- }
400
- else
401
- {
402
- return "";
403
- }
404
- }
405
- }
406
-
407
- //check for existing functions since we didn't use a prefix for this function
408
- if(!function_exists("cleanPhone"))
409
- {
410
- /**
411
- * Function to remove special characters from a phone number.
412
- * NOTE: Could probably replace with preg_replace("[^0-9]", "", $phone)
413
- *
414
- * @since 1.0
415
- *
416
- * @param string $phone The phone number to clean.
417
- */
418
- function cleanPhone($phone)
419
- {
420
- //if a + is passed, just pass it along
421
- if(strpos($phone, "+") !== false)
422
- return $phone;
423
- //clean the phone
424
- $phone = str_replace("-", "", $phone);
425
- $phone = str_replace(".", "", $phone);
426
- $phone = str_replace("(", "", $phone);
427
- $phone = str_replace(")", "", $phone);
428
- $phone = str_replace(" ", "", $phone);
429
- return $phone;
430
- }
431
- }
432
-
433
- //check for existing functions since we didn't use a prefix for this function
434
- if(!function_exists("formatPhone"))
435
- {
436
- /**
437
- * Function to format a phone number.
438
- *
439
- * @since 1.0
440
- *
441
- * @param string $phone The phone number to format.
442
- */
443
- function formatPhone($phone)
444
- {
445
- $r = cleanPhone($phone);
446
-
447
- if(strlen($r) == 11)
448
- $r = substr($r, 0, 1) . " (" . substr($r, 1, 3) . ") " . substr($r, 4, 3) . "-" . substr($r, 7, 4);
449
- elseif(strlen($r) == 10)
450
- $r = "(" . substr($r, 0, 3) . ") " . substr($r, 3, 3) . "-" . substr($r, 6, 4);
451
- elseif(strlen($r) == 7)
452
- $r = substr($r, 0, 3) . "-" . substr($r, 3, 4);
453
-
454
- /**
455
- * Filter to do more or less cleaning of phone numbers.
456
- *
457
- * @since 1.8.4.4
458
- *
459
- * @param string $r The formatted phone number.
460
- * @param string $phone The original phone number.
461
- */
462
- return apply_filters('pmpro_format_phone', $r, $phone);
463
- }
464
- }
465
-
466
- function pmpro_showRequiresMembershipMessage()
467
- {
468
- //TODO $current_user $post_membership_levels_names are undefined variables
469
- //get the correct message
470
- if(is_feed())
471
- {
472
- $content = pmpro_getOption("rsstext");
473
- $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content);
474
- }
475
- elseif($current_user->ID)
476
- {
477
- //not a member
478
- $content = pmpro_getOption("nonmembertext");
479
- $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content);
480
- }
481
- else
482
- {
483
- //not logged in!
484
- $content = pmpro_getOption("notloggedintext");
485
- $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content);
486
- }
487
- }
488
-
489
- /* pmpro_hasMembershipLevel() checks if the passed user is a member of the passed level
490
- *
491
- * $level may either be the ID or name of the desired membership_level. (or an array of such)
492
- * If $user_id is omitted, the value will be retrieved from $current_user.
493
- *
494
- * Return values:
495
- * Success returns boolean true.
496
- * Failure returns a string containing the error message.
497
- */
498
- function pmpro_hasMembershipLevel($levels = NULL, $user_id = NULL)
499
- {
500
- global $current_user, $all_membership_levels, $wpdb;
501
-
502
- $return = false;
503
-
504
- if(empty($user_id)) //no user_id passed, check the current user
505
- {
506
- $user_id = $current_user->ID;
507
- $membership_levels = $current_user->membership_levels;
508
- }
509
- elseif(is_numeric($user_id)) //get membership levels for given user
510
- {
511
- $membership_levels = pmpro_getMembershipLevelsForUser($user_id);
512
- }
513
- else
514
- return false; //invalid user_id
515
-
516
- if($levels === "0" || $levels === 0) //if 0 was passed, return true if they have no level and false if they have any
517
- {
518
- $return = empty($membership_levels);
519
- }
520
- elseif(empty($levels)) //if no level var was passed, we're just checking if they have any level
521
- {
522
- $return = !empty($membership_levels);
523
- }
524
- else
525
- {
526
- if(!is_array($levels)) //make an array out of a single element so we can use the same code
527
- {
528
- $levels = array($levels);
529
- }
530
-
531
- if(empty($membership_levels))
532
- {
533
- //user has no levels just check if 0, L, or -L was sent in one of the levels
534
- if(in_array(0, $levels, true) || in_array("0", $levels))
535
- $return = true;
536
- elseif(in_array("L", $levels) || in_array("l", $levels))
537
- $return = (!empty($user_id) && $user_id == $current_user->ID);
538
- elseif(in_array("-L", $levels) || in_array("-l", $levels))
539
- $return = (empty($user_id) || $user_id != $current_user->ID);
540
- }
541
- else
542
- {
543
- foreach($levels as $level)
544
- {
545
- if(strtoupper($level) == "L")
546
- {
547
- //checking if user is logged in
548
- if(!empty($user_id) && $user_id == $current_user->ID)
549
- $return = true;
550
- }
551
- elseif(strtoupper($level) == "-L")
552
- {
553
- //checking if user is logged out
554
- if(empty($user_id) || $user_id != $current_user->ID)
555
- $return = true;
556
- }
557
- elseif($level == "0")
558
- {
559
- continue; //user with levels so not a "non-member"
560
- }
561
- else
562
- {
563
- //checking a level id
564
- $level_obj = pmpro_getLevel(is_numeric($level) ? abs(intval($level)) : $level); //make sure our level is in a proper format
565
- if(empty($level_obj)){continue;} //invalid level
566
- $found_level = false;
567
- foreach($membership_levels as $membership_level)
568
- {
569
- if($membership_level->id == $level_obj->id) //found a match
570
- {
571
- $found_level = true;
572
- }
573
- }
574
-
575
- if(is_numeric($level) && intval($level) < 0 && !$found_level) //checking for the absence of this level and they don't have it
576
- {
577
- $return = true;
578
- }
579
- elseif(is_numeric($level) && intval($level) > 0 && $found_level) //checking for the presence of this level and they have it
580
- {
581
- $return = true;
582
- }
583
- elseif(!is_numeric($level)) //if a level name was passed
584
- $return = $found_level;
585
- }
586
- }
587
- }
588
- }
589
-
590
- $return = apply_filters("pmpro_has_membership_level", $return, $user_id, $levels);
591
- return $return;
592
- }
593
-
594
- /* pmpro_changeMembershipLevel() creates or updates the membership level of the given user to the given level.
595
- *
596
- * $level may either be the ID or name of the desired membership_level.
597
- * If $user_id is omitted, the value will be retrieved from $current_user.
598
- *
599
- * Return values:
600
- * Success returns boolean true.
601
- * Failure returns boolean false.
602
- */
603
- function pmpro_changeMembershipLevel($level, $user_id = NULL, $old_level_status = 'inactive')
604
- {
605
- global $wpdb;
606
- global $current_user, $pmpro_error;
607
-
608
- if(empty($user_id))
609
- {
610
- $user_id = $current_user->ID;
611
- }
612
-
613
- if(empty($user_id))
614
- {
615
- $pmpro_error = __("User ID not found.", "pmpro");
616
- return false;
617
- }
618
-
619
- //make sure user id is int for security
620
- $user_id = intval($user_id);
621
-
622
- if(empty($level)) //cancelling membership
623
- {
624
- $level = 0;
625
- }
626
- else if(is_array($level))
627
- {
628
- //custom level
629
- }
630
- else
631
- {
632
- $level_obj = pmpro_getLevel($level);
633
- if(empty($level_obj))
634
- {
635
- $pmpro_error = __("Invalid level.", "pmpro");
636
- return false;
637
- }
638
- $level = $level_obj->id;
639
- }
640
-
641
- //if it's a custom level, they're changing
642
- if(!is_array($level))
643
- {
644
- //are they even changing?
645
- if(pmpro_hasMembershipLevel($level, $user_id)) {
646
- $pmpro_error = __("not changing?", "pmpro");
647
- return false; //not changing
648
- }
649
- }
650
-
651
- //get all active membershipships for this user
652
- $old_levels = pmpro_getMembershipLevelsForUser($user_id);
653
-
654
- //deactivate old memberships based on the old_level_status passed in (updates pmpro_memberships_users table)
655
- if($old_levels)
656
- {
657
- foreach($old_levels as $old_level) {
658
-
659
- $sql = "UPDATE $wpdb->pmpro_memberships_users SET `status`='$old_level_status', `enddate`='" . current_time('mysql') . "' WHERE `id`=".$old_level->subscription_id;
660
-
661
- if(!$wpdb->query($sql))
662
- {
663
- $pmpro_error = __("Error interacting with database", "pmpro") . ": ".(mysql_errno()?mysql_error():'unavailable');
664
-
665
- return false;
666
- }
667
- }
668
- }
669
-
670
- //should we cancel their gateway subscriptions?
671
- $pmpro_cancel_previous_subscriptions = true;
672
- if(isset($_REQUEST['cancel_membership']) && $_REQUEST['cancel_membership'] == false)
673
- $pmpro_cancel_previous_subscriptions = false;
674
- $pmpro_cancel_previous_subscriptions = apply_filters("pmpro_cancel_previous_subscriptions", $pmpro_cancel_previous_subscriptions);
675
-
676
- //cancel any other subscriptions they have (updates pmpro_membership_orders table)
677
- if($pmpro_cancel_previous_subscriptions)
678
- {
679
- $other_order_ids = $wpdb->get_col("SELECT id FROM $wpdb->pmpro_membership_orders WHERE user_id = '" . $user_id . "' AND status = 'success' ORDER BY id DESC");
680
-
681
- foreach($other_order_ids as $order_id)
682
- {
683
- $c_order = new MemberOrder($order_id);
684
- $c_order->cancel();
685
-
686
- if(!empty($c_order->error))
687
- $pmpro_error = $c_order->error;
688
- }
689
- }
690
-
691
- //insert current membership
692
- if(!empty($level)) //are we getting a new one or just cancelling the old ones
693
- {
694
- if(is_array($level))
695
- {
696
- //make sure the dates are in good formats
697
- if($level['startdate'] != current_time('mysql') && $level['startdate'] != "NULL" && substr($level['startdate'], 0, 1) != "'")
698
- $level['startdate'] = "'" . $level['startdate'] . "'";
699
-
700
- if($level['enddate'] != current_time('mysql') && $level['enddate'] != "NULL" && substr($level['enddate'], 0, 1) != "'")
701
- $level['enddate'] = "'" . $level['enddate'] . "'";
702
-
703
- //Better support mySQL Strict Mode by passing a proper enum value for cycle_period
704
- if ($level['cycle_period'] == '') $level['cycle_period'] = 0;
705
-
706
- $sql = "INSERT INTO $wpdb->pmpro_memberships_users (user_id, membership_id, code_id, initial_payment, billing_amount, cycle_number, cycle_period, billing_limit, trial_amount, trial_limit, startdate, enddate)
707
- VALUES('" . $level['user_id'] . "',
708
- '" . $level['membership_id'] . "',
709
- '" . intval($level['code_id']) . "',
710
- '" . $level['initial_payment'] . "',
711
- '" . $level['billing_amount'] . "',
712
- '" . $level['cycle_number'] . "',
713
- '" . $level['cycle_period'] . "',
714
- '" . $level['billing_limit'] . "',
715
- '" . $level['trial_amount'] . "',
716
- '" . $level['trial_limit'] . "',
717
- " . $level['startdate'] . ",
718
- " . $level['enddate'] . ")";
719
-
720
- if(!$wpdb->query($sql))
721
- {
722
- $pmpro_error = __("Error interacting with database", "pmpro") . ": ".(mysql_errno()?mysql_error():'unavailable');
723
- return false;
724
- }
725
- }
726
- else
727
- {
728
- $sql = "INSERT INTO $wpdb->pmpro_memberships_users (user_id, membership_id, code_id, initial_payment, billing_amount, cycle_number, cycle_period, billing_limit, trial_amount, trial_limit, startdate, enddate)
729
- VALUES (
730
- '" . $user_id . "',
731
- '" . $level . "',
732
- '0',
733
- '0',
734
- '0',
735
- '0',
736
- '0',
737
- '0',
738
- '0',
739
- '0',
740
- '" . current_time('mysql') . "',
741
- '0000-00-00 00:00:00'
742
- )";
743
-
744
- if(!$wpdb->query($sql))
745
- {
746
- $pmpro_error = __("Error interacting with database", "pmpro") . ": ".(mysql_errno()?mysql_error():'unavailable');
747
- return false;
748
- }
749
- }
750
- }
751
-
752
- //get level id
753
- if(is_array($level))
754
- $level_id = $level['membership_id']; //custom level
755
- else
756
- $level_id = $level; //just id
757
-
758
- //remove cached level
759
- global $all_membership_levels;
760
- unset($all_membership_levels[$user_id]);
761
-
762
- //update user data and call action
763
- pmpro_set_current_user();
764
- do_action("pmpro_after_change_membership_level", $level_id, $user_id); //$level is the $level_id here
765
- return true;
766
- }
767
-
768
- /* pmpro_toggleMembershipCategory() creates or deletes a linking entry between the membership level and post category tables.
769
- *
770
- * $level may either be the ID or name of the desired membership_level.
771
- * $category must be a valid post category ID.
772
- *
773
- * Return values:
774
- * Success returns boolean true.
775
- * Failure returns a string containing the error message.
776
- */
777
- function pmpro_toggleMembershipCategory( $level, $category, $value )
778
- {
779
- global $wpdb;
780
- $category = intval($category);
781
-
782
- if ( ($level = intval($level)) <= 0 )
783
- {
784
- $safe = addslashes($level);
785
- if ( ($level = intval($wpdb->get_var("SELECT id FROM {$wpdb->pmpro_membership_levels} WHERE name = '$safe' LIMIT 1"))) <= 0 )
786
- {
787
- return __("Membership level not found.", "pmpro");
788
- }
789
- }
790
-
791
- if ( $value )
792
- {
793
- $sql = "REPLACE INTO {$wpdb->pmpro_memberships_categories} (`membership_id`,`category_id`) VALUES ('$level','$category')";
794
- $wpdb->query($sql);
795
- if(mysql_errno()) return mysql_error();
796
- }
797
- else
798
- {
799
- $sql = "DELETE FROM {$wpdb->pmpro_memberships_categories} WHERE `membership_id` = '$level' AND `category_id` = '$category' LIMIT 1";
800
- $wpdb->query($sql);
801
- if(mysql_errno()) return mysql_error();
802
- }
803
-
804
- return true;
805
- }
806
-
807
- /* pmpro_updateMembershipCategories() ensures that all those and only those categories given
808
- * are associated with the given membership level.
809
- *
810
- * $level is a valid membership level ID or name
811
- * $categories is an array of post category IDs
812
- *
813
- * Return values:
814
- * Success returns boolean true.
815
- * Failure returns a string containing the error message.
816
- */
817
- function pmpro_updateMembershipCategories($level, $categories)
818
- {
819
- global $wpdb;
820
-
821
- if(!is_numeric($level))
822
- {
823
- $level = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_levels WHERE name = '" . esc_sql($level) . "' LIMIT 1");
824
- if(empty($level))
825
- {
826
- return __("Membership level not found.", "pmpro");
827
- }
828
- }
829
-
830
- // remove all existing links...
831
- $sqlQuery = "DELETE FROM $wpdb->pmpro_memberships_categories WHERE `membership_id` = '" . esc_sql($level) . "'";
832
- $wpdb->query($sqlQuery);
833
- if(mysql_errno()) return mysql_error();
834
-
835
- // add the given links [back?] in...
836
- foreach($categories as $cat)
837
- {
838
- if(is_string($r = pmpro_toggleMembershipCategory( $level, $cat, true)))
839
- {
840
- //uh oh, error
841
- return $r;
842
- }
843
- }
844
-
845
- //all good
846
- return true;
847
- }
848
-
849
- /* pmpro_getMembershipCategories() returns the categories for a given level
850
- *
851
- * $level_id is a valid membership level ID
852
- *
853
- * Return values:
854
- * Success returns boolean true.
855
- * Failure returns boolean false.
856
- */
857
- function pmpro_getMembershipCategories($level_id)
858
- {
859
- $level_id = intval($level_id);
860
-
861
- global $wpdb;
862
- $categories = $wpdb->get_col("SELECT c.category_id
863
- FROM {$wpdb->pmpro_memberships_categories} AS c
864
- WHERE c.membership_id = '" . $level_id . "'");
865
-
866
- return $categories;
867
- }
868
-
869
-
870
- function pmpro_isAdmin($user_id = NULL)
871
- {
872
- global $current_user, $wpdb;
873
- if(!$user_id)
874
- $user_id = $current_user->ID;
875
-
876
- if(!$user_id)
877
- return false;
878
-
879
- $admincap = user_can($user_id, "manage_options");
880
- if($admincap)
881
- return true;
882
- else
883
- return false;
884
- }
885
-
886
- function pmpro_replaceUserMeta($user_id, $meta_keys, $meta_values, $prev_values = NULL)
887
- {
888
- //expects all arrays for last 3 params or all strings
889
- if(!is_array($meta_keys))
890
- {
891
- $meta_keys = array($meta_keys);
892
- $meta_values = array($meta_values);
893
- $prev_values = array($prev_values);
894
- }
895
-
896
- for($i = 0; $i < count($meta_values); $i++)
897
- {
898
- if($prev_values[$i])
899
- {
900
- update_user_meta($user_id, $meta_keys[$i], $meta_values[$i], $prev_values[$i]);
901
- }
902
- else
903
- {
904
- $old_value = get_user_meta($user_id, $meta_keys[$i], true);
905
- if($old_value)
906
- {
907
- update_user_meta($user_id, $meta_keys[$i], $meta_values[$i], $old_value);
908
- }
909
- else
910
- {
911
- update_user_meta($user_id, $meta_keys[$i], $meta_values[$i]);
912
- }
913
- }
914
- }
915
-
916
- return $i;
917
- }
918
-
919
- function pmpro_getMetavalues($query)
920
- {
921
- global $wpdb;
922
-
923
- $results = $wpdb->get_results($query);
924
- $r = new stdClass();
925
- foreach($results as $result)
926
- {
927
- if(!empty($r))
928
- $r->{$result->key} = $result->value;
929
- }
930
-
931
- return $r;
932
- }
933
-
934
- //function to return the pagination string
935
- function pmpro_getPaginationString($page = 1, $totalitems, $limit = 15, $adjacents = 1, $targetpage = "/", $pagestring = "&pn=")
936
- {
937
- //defaults
938
- if(!$adjacents) $adjacents = 1;
939
- if(!$limit) $limit = 15;
940
- if(!$page) $page = 1;
941
- if(!$targetpage) $targetpage = "/";
942
-
943
- //other vars
944
- $prev = $page - 1; //previous page is page - 1
945
- $next = $page + 1; //next page is page + 1
946
- $lastpage = ceil($totalitems / $limit); //lastpage is = total items / items per page, rounded up.
947
- $lpm1 = $lastpage - 1; //last page minus 1
948
-
949
- /*
950
- Now we apply our rules and draw the pagination object.
951
- We're actually saving the code to a variable in case we want to draw it more than once.
952
- */
953
- $pagination = "";
954
- if($lastpage > 1)
955
- {
956
- $pagination .= "<div class=\"pmpro_pagination\"";
957
- if(!empty($margin) || !empty($padding))
958
- {
959
- $pagination .= " style=\"";
960
- if($margin)
961
- $pagination .= "margin: $margin;";
962
- if($padding)
963
- $pagination .= "padding: $padding;";
964
- $pagination .= "\"";
965
- }
966
- $pagination .= ">";
967
-
968
- //previous button
969
- if ($page > 1)
970
- $pagination .= "<a href=\"$targetpage$pagestring$prev\">&laquo; prev</a>";
971
- else
972
- $pagination .= "<span class=\"disabled\">&laquo; prev</span>";
973
-
974
- //pages
975
- if ($lastpage < 7 + ($adjacents * 2)) //not enough pages to bother breaking it up
976
- {
977
- for ($counter = 1; $counter <= $lastpage; $counter++)
978
- {
979
- if ($counter == $page)
980
- $pagination .= "<span class=\"current\">$counter</span>";
981
- else
982
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
983
- }
984
- }
985
- elseif($lastpage >= 7 + ($adjacents * 2)) //enough pages to hide some
986
- {
987
- //close to beginning; only hide later pages
988
- if($page < 1 + ($adjacents * 3))
989
- {
990
- for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++)
991
- {
992
- if ($counter == $page)
993
- $pagination .= "<span class=\"current\">$counter</span>";
994
- else
995
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
996
- }
997
- $pagination .= "...";
998
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $lpm1 . "\">$lpm1</a>";
999
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $lastpage . "\">$lastpage</a>";
1000
- }
1001
- //in middle; hide some front and some back
1002
- elseif($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2))
1003
- {
1004
- $pagination .= "<a href=\"" . $targetpage . $pagestring . "1\">1</a>";
1005
- $pagination .= "<a href=\"" . $targetpage . $pagestring . "2\">2</a>";
1006
- $pagination .= "...";
1007
- for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++)
1008
- {
1009
- if ($counter == $page)
1010
- $pagination .= "<span class=\"current\">$counter</span>";
1011
- else
1012
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
1013
- }
1014
- $pagination .= "...";
1015
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $lpm1 . "\">$lpm1</a>";
1016
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $lastpage . "\">$lastpage</a>";
1017
- }
1018
- //close to end; only hide early pages
1019
- else
1020
- {
1021
- $pagination .= "<a href=\"" . $targetpage . $pagestring . "1\">1</a>";
1022
- $pagination .= "<a href=\"" . $targetpage . $pagestring . "2\">2</a>";
1023
- $pagination .= "...";
1024
- for ($counter = $lastpage - (1 + ($adjacents * 3)); $counter <= $lastpage; $counter++)
1025
- {
1026
- if ($counter == $page)
1027
- $pagination .= "<span class=\"current\">$counter</span>";
1028
- else
1029
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
1030
- }
1031
- }
1032
- }
1033
-
1034
- //next button
1035
- if ($page < $counter - 1)
1036
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $next . "\">next &raquo;</a>";
1037
- else
1038
- $pagination .= "<span class=\"disabled\">next &raquo;</span>";
1039
- $pagination .= "</div>\n";
1040
- }
1041
-
1042
- return $pagination;
1043
-
1044
- }
1045
-
1046
- function pmpro_calculateInitialPaymentRevenue($s = NULL, $l = NULL)
1047
- {
1048
- global $wpdb;
1049
-
1050
- //if we're limiting users by search
1051
- if($s || $l)
1052
- {
1053
- $user_ids_query = "SELECT u.ID FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id WHERE mu.status = 'active' ";
1054
- if($s)
1055
- $user_ids_query .= "AND (u.user_login LIKE '%" . esc_sql($s) . "%' OR u.user_email LIKE '%" . esc_sql($s) . "%' OR um.meta_value LIKE '%$" . esc_sql(s) . "%') ";
1056
- if($l)
1057
- $user_ids_query .= "AND mu.membership_id = '" . esc_sql($l) . "' ";
1058
- }
1059
-
1060
- //query to sum initial payments
1061
- $sqlQuery = "SELECT SUM(initial_payment) FROM $wpdb->pmpro_memberships_users WHERE `status` = 'active' ";
1062
- if(!empty($user_ids_query))
1063
- $sqlQuery .= "AND user_id IN(" . $user_ids_query . ") ";
1064
-
1065
- $total = $wpdb->get_var($sqlQuery);
1066
-
1067
- return (double)$total;
1068
- }
1069
-
1070
- function pmpro_calculateRecurringRevenue($s, $l)
1071
- {
1072
- global $wpdb;
1073
-
1074
- //if we're limiting users by search
1075
- if($s || $l)
1076
- {
1077
- $user_ids_query = "AND user_id IN(SELECT u.ID FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id WHERE mu.status = 'active' ";
1078
- if($s)
1079
- $user_ids_query .= "AND (u.user_login LIKE '%" . esc_sql($s) . "%' OR u.user_email LIKE '%" . esc_sql($s) . "%' OR um.meta_value LIKE '%" . esc_sql($s) . "%') ";
1080
- if($l)
1081
- $user_ids_query .= "AND mu.membership_id = '" . esc_sql($l) . "' ";
1082
- $user_ids_query .= ")";
1083
- }
1084
- else
1085
- $user_ids_query = "";
1086
-
1087
- //4 queries to get annual earnings for each cycle period. currently ignoring trial periods and billing limits.
1088
- $sqlQuery = "
1089
- SELECT SUM((12/cycle_number)*billing_amount) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND cycle_period = 'Month' AND cycle_number <> 12 $user_ids_query
1090
- UNION
1091
- SELECT SUM((365/cycle_number)*billing_amount) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND cycle_period = 'Day' AND cycle_number <> 365 $user_ids_query
1092
- UNION
1093
- SELECT SUM((52/cycle_number)*billing_amount) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND cycle_period = 'Week' AND cycle_number <> 52 $user_ids_query
1094
- UNION
1095
- SELECT SUM(billing_amount) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND cycle_period = 'Year' $user_ids_query
1096
- ";
1097
-
1098
- $annual_revenues = $wpdb->get_col($sqlQuery);
1099
-
1100
- $total = 0;
1101
- foreach($annual_revenues as $r)
1102
- {
1103
- $total += $r;
1104
- }
1105
-
1106
- return $total;
1107
- }
1108
-
1109
- function pmpro_generateUsername($firstname = "", $lastname = "", $email = "")
1110
- {
1111
- global $wpdb;
1112
-
1113
- //try first initial + last name, firstname, lastname
1114
- $firstname = preg_replace("/[^A-Za-z]/", "", $firstname);
1115
- $lastname = preg_replace("/[^A-Za-z]/", "", $lastname);
1116
- if($firstname && $lastname)
1117
- {
1118
- $username = substr($firstname, 0, 1) . $lastname;
1119
- }
1120
- elseif($firstname)
1121
- {
1122
- $username = $firstname;
1123
- }
1124
- elseif($lastname)
1125
- {
1126
- $username = $lastname;
1127
- }
1128
-
1129
- //is it taken?
1130
- $taken = $wpdb->get_var("SELECT user_login FROM $wpdb->users WHERE user_login = '" . esc_sql($username) . "' LIMIT 1");
1131
-
1132
- if(!$taken)
1133
- return $username;
1134
-
1135
- //try the beginning of the email address
1136
- $emailparts = explode("@", $email);
1137
- if(is_array($emailparts))
1138
- $email = preg_replace("/[^A-Za-z]/", "", $emailparts[0]);
1139
-
1140
- if(!empty($email))
1141
- {
1142
- $username = $email;
1143
- }
1144
-
1145
- //is this taken? if not, add numbers until it works
1146
- $taken = true;
1147
- $count = 0;
1148
- while($taken)
1149
- {
1150
- //add a # to the end
1151
- if($count)
1152
- {
1153
- $username = preg_replace("/[0-9]/", "", $username) . $count;
1154
- }
1155
-
1156
- //taken?
1157
- $taken = $wpdb->get_var("SELECT user_login FROM $wpdb->users WHERE user_login = '" . esc_sql($username) . "' LIMIT 1");
1158
-
1159
- //increment the number
1160
- $count++;
1161
- }
1162
-
1163
- //must have a good username now
1164
- return $username;
1165
- }
1166
-
1167
- //get a new random code for discount codes
1168
- function pmpro_getDiscountCode($seed = NULL)
1169
- {
1170
- global $wpdb;
1171
-
1172
- while(empty($code))
1173
- {
1174
- $scramble = md5(AUTH_KEY . current_time('timestamp') . $seed . SECURE_AUTH_KEY);
1175
- $code = substr($scramble, 0, 10);
1176
- $check = $wpdb->get_var("SELECT code FROM $wpdb->pmpro_discount_codes WHERE code = '" . esc_sql($code) . "' LIMIT 1");
1177
- if($check || is_numeric($code))
1178
- $code = NULL;
1179
- }
1180
-
1181
- return strtoupper($code);
1182
- }
1183
-
1184
- //is a discount code valid
1185
- function pmpro_checkDiscountCode($code, $level_id = NULL, $return_errors = false)
1186
- {
1187
- global $wpdb;
1188
-
1189
- $error = false;
1190
-
1191
- //make sure level id is int for security
1192
- $level_id = intval($level_id);
1193
-
1194
- //no code, no code
1195
- if(empty($code))
1196
- $error = __("No code was given to check.", "pmpro");
1197
-
1198
- //get code from db
1199
- if(!$error)
1200
- {
1201
- $dbcode = $wpdb->get_row("SELECT *, UNIX_TIMESTAMP(starts) as starts, UNIX_TIMESTAMP(expires) as expires FROM $wpdb->pmpro_discount_codes WHERE code ='" . esc_sql($code) . "' LIMIT 1");
1202
-
1203
- //did we find it?
1204
- if(empty($dbcode->id))
1205
- $error = __("The discount code could not be found.", "pmpro");
1206
- }
1207
-
1208
- //check if the code has started
1209
- if(!$error)
1210
- {
1211
- //fix the date timestamps
1212
- $dbcode->starts = strtotime(date("m/d/Y", $dbcode->starts));
1213
- $dbcode->expires = strtotime(date("m/d/Y", $dbcode->expires));
1214
-
1215
- //today
1216
- $today = strtotime(date("m/d/Y 00:00:00", current_time("timestamp")));
1217
-
1218
- //has this code started yet?
1219
- if(!empty($dbcode->starts) && $dbcode->starts > $today)
1220
- $error = sprintf(__("This discount code goes into effect on %s.", "pmpro"), date(get_option('date_format'), $dbcode->starts));
1221
- }
1222
-
1223
- //check if the code is expired
1224
- if(!$error)
1225
- {
1226
- if(!empty($dbcode->expires) && $dbcode->expires < $today)
1227
- $error = sprintf(__("This discount code expired on %s.", "pmpro"), date(get_option('date_format'), $dbcode->expires));
1228
- }
1229
-
1230
- //have we run out of uses?
1231
- if(!$error)
1232
- {
1233
- if($dbcode->uses > 0)
1234
- {
1235
- $used = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->pmpro_discount_codes_uses WHERE code_id = '" . $dbcode->id . "'");
1236
- if($used >= $dbcode->uses)
1237
- $error = __("This discount code is no longer valid.", "pmpro");
1238
- }
1239
- }
1240
-
1241
- //if a level was passed check if this code applies
1242
- if(!$error)
1243
- {
1244
- $pmpro_check_discount_code_levels = apply_filters("pmpro_check_discount_code_levels", true, $dbcode->id);
1245
- if(!empty($level_id) && $pmpro_check_discount_code_levels)
1246
- {
1247
- $code_level = $wpdb->get_row("SELECT l.id, cl.*, l.name, l.description, l.allow_signups FROM $wpdb->pmpro_discount_codes_levels cl LEFT JOIN $wpdb->pmpro_membership_levels l ON cl.level_id = l.id WHERE cl.code_id = '" . $dbcode->id . "' AND cl.level_id = '" . $level_id . "' LIMIT 1");
1248
-
1249
- if(empty($code_level))
1250
- $error = __("This discount code does not apply to this membership level.", "pmpro");
1251
- }
1252
- }
1253
-
1254
- //allow filter
1255
- $pmpro_check_discount_code = apply_filters("pmpro_check_discount_code", !$error, $dbcode, $level_id, $code);
1256
- if(is_string($pmpro_check_discount_code))
1257
- $error = $pmpro_check_discount_code; //string returned, this is an error
1258
- elseif(!$pmpro_check_discount_code && !$error)
1259
- $error = true; //no error before, but filter returned error
1260
- elseif($pmpro_check_discount_code)
1261
- $error = false; //filter is true, so error false
1262
-
1263
- //return
1264
- if($error)
1265
- {
1266
- //there was an error
1267
- if(!empty($return_errors))
1268
- return array(false, $error);
1269
- else
1270
- return false;
1271
- }
1272
- else
1273
- {
1274
- //guess we're all good
1275
- if(!empty($return_errors))
1276
- return array(true, __("This discount code is okay.", "pmpro"));
1277
- else
1278
- return true;
1279
- }
1280
- }
1281
-
1282
- function pmpro_no_quotes($s, $quotes = array("'", '"'))
1283
- {
1284
- return str_replace($quotes, "", $s);
1285
- }
1286
-
1287
- //from: http://www.php.net/manual/en/function.implode.php#86845
1288
- function pmpro_implodeToEnglish($array)
1289
- {
1290
- // sanity check
1291
- if (!$array || !count ($array))
1292
- return '';
1293
-
1294
- // get last element
1295
- $last = array_pop ($array);
1296
-
1297
- // if it was the only element - return it
1298
- if (!count ($array))
1299
- return $last;
1300
-
1301
- return implode (', ', $array).' ' . __('and', 'pmpro') . ' '.$last;
1302
- }
1303
-
1304
- //from yoast wordpress seo
1305
- function pmpro_text_limit( $text, $limit, $finish = '&hellip;')
1306
- {
1307
- if( strlen( $text ) > $limit ) {
1308
- $text = substr( $text, 0, $limit );
1309
- $text = substr( $text, 0, - ( strlen( strrchr( $text,' ') ) ) );
1310
- $text .= $finish;
1311
- }
1312
- return $text;
1313
- }
1314
-
1315
- /* pmpro_getMembershipLevelForUser() returns the first active membership level for a user
1316
- *
1317
- * If $user_id is omitted, the value will be retrieved from $current_user.
1318
- *
1319
- * Return values:
1320
- * Success returns the level object.
1321
- * Failure returns false.
1322
- */
1323
- function pmpro_getMembershipLevelForUser($user_id = NULL, $force = false)
1324
- {
1325
- if(empty($user_id))
1326
- {
1327
- global $current_user;
1328
- $user_id = $current_user->ID;
1329
- }
1330
-
1331
- if(empty($user_id))
1332
- {
1333
- return false;
1334
- }
1335
-
1336
- //make sure user id is int for security
1337
- $user_id = intval($user_id);
1338
-
1339
- global $all_membership_levels;
1340
-
1341
- if(isset($all_membership_levels[$user_id]) && !$force)
1342
- {
1343
- return $all_membership_levels[$user_id];
1344
- }
1345
- else
1346
- {
1347
- global $wpdb;
1348
- $all_membership_levels[$user_id] = $wpdb->get_row("SELECT
1349
- l.id AS ID,
1350
- l.id as id,
1351
- mu.id as subscription_id,
1352
- l.name AS name,
1353
- l.description,
1354
- l.expiration_number,
1355
- l.expiration_period,
1356
- mu.initial_payment,
1357
- mu.billing_amount,
1358
- mu.cycle_number,
1359
- mu.cycle_period,
1360
- mu.billing_limit,
1361
- mu.trial_amount,
1362
- mu.trial_limit,
1363
- mu.code_id as code_id,
1364
- UNIX_TIMESTAMP(startdate) as startdate,
1365
- UNIX_TIMESTAMP(enddate) as enddate
1366
- FROM {$wpdb->pmpro_membership_levels} AS l
1367
- JOIN {$wpdb->pmpro_memberships_users} AS mu ON (l.id = mu.membership_id)
1368
- WHERE mu.user_id = $user_id AND mu.status = 'active'
1369
- LIMIT 1");
1370
- return $all_membership_levels[$user_id];
1371
- }
1372
- }
1373
-
1374
- /* pmpro_getMembershipLevelsForUser() returns the membership levels for a user
1375
- *
1376
- * If $user_id is omitted, the value will be retrieved from $current_user.
1377
- * By default it only includes actvie memberships.
1378
- *
1379
- * Return values:
1380
- * Success returns an array of level objects.
1381
- * Failure returns false.
1382
- */
1383
- function pmpro_getMembershipLevelsForUser($user_id = NULL, $include_inactive = false)
1384
- {
1385
- if(empty($user_id))
1386
- {
1387
- global $current_user;
1388
- $user_id = $current_user->ID;
1389
- }
1390
-
1391
- if(empty($user_id))
1392
- {
1393
- return false;
1394
- }
1395
-
1396
- //make sure user id is int for security
1397
- $user_id = intval($user_id);
1398
-
1399
- global $wpdb;
1400
- return $wpdb->get_results("SELECT
1401
- l.id AS ID,
1402
- l.id as id,
1403
- mu.id as subscription_id,
1404
- l.name,
1405
- l.description,
1406
- l.expiration_number,
1407
- l.expiration_period,
1408
- mu.initial_payment,
1409
- mu.billing_amount,
1410
- mu.cycle_number,
1411
- mu.cycle_period,
1412
- mu.billing_limit,
1413
- mu.trial_amount,
1414
- mu.trial_limit,
1415
- mu.code_id as code_id,
1416
- UNIX_TIMESTAMP(startdate) as startdate,
1417
- UNIX_TIMESTAMP(enddate) as enddate
1418
- FROM {$wpdb->pmpro_membership_levels} AS l
1419
- JOIN {$wpdb->pmpro_memberships_users} AS mu ON (l.id = mu.membership_id)
1420
- WHERE mu.user_id = $user_id".($include_inactive?"":" AND mu.status = 'active'"));
1421
- }
1422
-
1423
- /* pmpro_getLevel() returns the level object for a level
1424
- *
1425
- * $level may be the level id or name
1426
- *
1427
- * Return values:
1428
- * Success returns the level object.
1429
- * Failure returns false.
1430
- */
1431
- function pmpro_getLevel($level)
1432
- {
1433
- global $pmpro_levels;
1434
-
1435
- if(is_object($level) && !empty($level->id))
1436
- $level = $level->id;
1437
-
1438
- //was a name passed? (Todo: make sure level names have at least one non-numeric character.
1439
- if(is_numeric($level))
1440
- {
1441
- $level_id = intval($level);
1442
- if(isset($pmpro_levels[$level_id]))
1443
- {
1444
- return $pmpro_levels[$level_id];
1445
- }
1446
- else
1447
- {
1448
- global $wpdb;
1449
- $pmpro_levels[$level_id] = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . $level_id . "' LIMIT 1");
1450
- return $pmpro_levels[$level_id];
1451
- }
1452
- }
1453
- else
1454
- {
1455
- global $wpdb;
1456
- $level_obj = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE name = '" . esc_sql($level) . "' LIMIT 1");
1457
-
1458
- if(!empty($level_obj))
1459
- $level_id = $level_obj->id;
1460
- else
1461
- return false;
1462
-
1463
- $pmpro_levels[$level_id] = $level_obj;
1464
- return $pmpro_levels[$level_id];
1465
- }
1466
- }
1467
-
1468
- /*
1469
- Function to populate pmpro_levels with all levels. We query the DB every time just to be sure we have the latest.
1470
- This should be called if you want to be sure you get all levels as $pmpro_levels may only have a subset of levels.
1471
- */
1472
- function pmpro_getAllLevels($include_hidden = false, $force = false)
1473
- {
1474
- global $pmpro_levels, $wpdb;
1475
-
1476
- //just use what's cached (doesn't take into account include_hidden setting)
1477
- if(!empty($pmpro_levels) && !$force)
1478
- return $pmpro_levels;
1479
-
1480
- //build query
1481
- $sqlQuery = "SELECT * FROM $wpdb->pmpro_membership_levels ";
1482
- if(!$include_hidden)
1483
- $sqlQuery .= " WHERE allow_signups = 1 ORDER BY id";
1484
-
1485
- //get levels from the DB
1486
- $raw_levels = $wpdb->get_results($sqlQuery);
1487
-
1488
- //lets put them into an array where the key is the id of the level
1489
- $pmpro_levels = array();
1490
- foreach($raw_levels as $raw_level)
1491
- {
1492
- $pmpro_levels[$raw_level->id] = $raw_level;
1493
- }
1494
-
1495
- return $pmpro_levels;
1496
- }
1497
-
1498
- function pmpro_getCheckoutButton($level_id, $button_text = NULL, $classes = NULL)
1499
- {
1500
- if(empty($button_text))
1501
- $button_text = __("Sign Up for !!name!! Now", "pmpro");
1502
-
1503
- if(empty($classes))
1504
- $classes = "pmpro_btn";
1505
-
1506
- if(empty($level_id))
1507
- $r = __("Please specify a level id.", "pmpro");
1508
- else
1509
- {
1510
- //get level
1511
- $level = pmpro_getLevel($level_id);
1512
-
1513
- //replace vars
1514
- $replacements = array(
1515
- "!!id!!" => $level->id,
1516
- "!!name!!" => $level->name,
1517
- "!!description!!" => $level->description,
1518
- "!!confirmation!!" => $level->confirmation,
1519
- "!!initial_payment!!" => $level->initial_payment,
1520
- "!!billing_amount!!" => $level->billing_amount,
1521
- "!!cycle_number!!" => $level->cycle_number,
1522
- "!!cycle_period!!" => $level->cycle_period,
1523
- "!!billing_limit!!" => $level->billing_limit,
1524
- "!!trial_amount!!" => $level->trial_amount,
1525
- "!!trial_limit!!" => $level->trial_limit,
1526
- "!!expiration_number!!" => $level->expiration_number,
1527
- "!!expiration_period!!" => $level->expiration_period
1528
- );
1529
- $button_text = str_replace(array_keys($replacements), $replacements, $button_text);
1530
-
1531
- //button text
1532
- $r = "<a href=\"" . pmpro_url("checkout", "?level=" . $level_id) . "\" class=\"" . $classes . "\">" . $button_text . "</a>";
1533
- }
1534
- return $r;
1535
- }
1536
-
1537
- /**
1538
- * Get the "domain" from a URL. By domain, we mean the host name, minus any subdomains. So just the domain and TLD.
1539
- *
1540
- * @param string $url The URL to parse. (generally pass site_url() in WP)
1541
- * @return string The domain.
1542
- */
1543
- function pmpro_getDomainFromURL($url = NULL)
1544
- {
1545
- $domainparts = parse_url($url);
1546
- $domainparts = explode(".", $domainparts['host']);
1547
- if(count($domainparts) > 1)
1548
- {
1549
- //check for ips
1550
- $isip = true;
1551
- foreach($domainparts as $part)
1552
- {
1553
- if(!is_numeric($part))
1554
- {
1555
- $isip = false;
1556
- break;
1557
- }
1558
- }
1559
-
1560
- if($isip)
1561
- {
1562
- //ip, e.g. 127.1.1.1
1563
- $domain = implode(".", $domainparts);
1564
- }
1565
- else
1566
- {
1567
- //www.something.com, etc.
1568
- $domain = $domainparts[count($domainparts)-2] . "." . $domainparts[count($domainparts)-1];
1569
- }
1570
- }
1571
- else
1572
- {
1573
- //localhost or another single word domain
1574
- $domain = $domainparts[0];
1575
- }
1576
-
1577
- return $domain;
1578
- }
1579
-
1580
- /*
1581
- Get a member's start date... either in general or for a specific level_id.
1582
- */
1583
- if(!function_exists("pmpro_getMemberStartdate"))
1584
- {
1585
- function pmpro_getMemberStartdate($user_id = NULL, $level_id = 0)
1586
- {
1587
- if(empty($user_id))
1588
- {
1589
- global $current_user;
1590
- $user_id = $current_user->ID;
1591
- }
1592
-
1593
- //make sure user and level id are int for security
1594
- $user_id = intval($user_id);
1595
- $level_id = intval($level_id);
1596
-
1597
- global $pmpro_startdates; //for cache
1598
- if(empty($pmpro_startdates[$user_id][$level_id]))
1599
- {
1600
- global $wpdb;
1601
-
1602
- if(!empty($level_id))
1603
- $sqlQuery = "SELECT UNIX_TIMESTAMP(startdate) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND membership_id IN(" . esc_sql($level_id) . ") AND user_id = '" . $user_id . "' ORDER BY id LIMIT 1";
1604
- else
1605
- $sqlQuery = "SELECT UNIX_TIMESTAMP(startdate) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND user_id = '" . $user_id . "' ORDER BY id LIMIT 1";
1606
-
1607
- $startdate = apply_filters("pmpro_member_startdate", $wpdb->get_var($sqlQuery), $user_id, $level_id);
1608
-
1609
- $pmpro_startdates[$user_id][$level_id] = $startdate;
1610
- }
1611
-
1612
- return $pmpro_startdates[$user_id][$level_id];
1613
- }
1614
- }
1615
-
1616
- /*
1617
- How long has this member been a member
1618
- */
1619
- if(!function_exists("pmpro_getMemberDays"))
1620
- {
1621
- function pmpro_getMemberDays($user_id = NULL, $level_id = 0)
1622
- {
1623
- if(empty($user_id))
1624
- {
1625
- global $current_user;
1626
- $user_id = $current_user->ID;
1627
- }
1628
-
1629
- global $pmpro_member_days;
1630
- if(empty($pmpro_member_days[$user_id][$level_id]))
1631
- {
1632
- $startdate = pmpro_getMemberStartdate($user_id, $level_id);
1633
-
1634
- //check that there was a startdate at all
1635
- if(empty($startdate))
1636
- $pmpro_member_days[$user_id][$level_id] = 0;
1637
- else
1638
- {
1639
- $now = current_time('timestamp');
1640
- $days = ($now - $startdate)/3600/24;
1641
-
1642
- $pmpro_member_days[$user_id][$level_id] = $days;
1643
- }
1644
- }
1645
-
1646
- return $pmpro_member_days[$user_id][$level_id];
1647
- }
1648
- }
1649
-
1650
- //the start of a message handling script
1651
- function pmpro_setMessage($message, $type, $force = false)
1652
- {
1653
- global $pmpro_msg, $pmpro_msgt;
1654
-
1655
- //for now, we only show the first message generated
1656
- if($force || empty($pmpro_msg))
1657
- {
1658
- $pmpro_msg = $message;
1659
- $pmpro_msgt = $type;
1660
- }
1661
- }
1662
-
1663
- /**
1664
- * Show a a PMPro message set via pmpro_setMessage
1665
- *
1666
- * @since 1.8.5
1667
- */
1668
- function pmpro_showMessage()
1669
- {
1670
- global $pmpro_msg, $pmpro_msgt;
1671
-
1672
- if(!empty($pmpro_msg))
1673
- {
1674
- ?>
1675
- <div class="<?php echo $pmpro_msgt;?>">
1676
- <p><?php echo $pmpro_msg;?></p>
1677
- </div>
1678
- <?php
1679
- }
1680
- }
1681
-
1682
- //used in class definitions for input fields to see if there was an error
1683
- function pmpro_getClassForField($field)
1684
- {
1685
- global $pmpro_error_fields, $pmpro_required_billing_fields, $pmpro_required_user_fields;
1686
- $classes = array();
1687
-
1688
- //error on this field?
1689
- if(!empty($pmpro_error_fields) && in_array($field, $pmpro_error_fields))
1690
- {
1691
- $classes[] = "pmpro_error";
1692
- }
1693
-
1694
- if(is_array($pmpro_required_billing_fields) && is_array($pmpro_required_user_fields))
1695
- $required_fields = array_merge(array_keys($pmpro_required_billing_fields), array_keys($pmpro_required_user_fields));
1696
- elseif(is_array($pmpro_required_billing_fields))
1697
- $required_fields = array_keys($pmpro_required_billing_fields);
1698
- elseif(is_array($pmpro_required_user_fields))
1699
- $required_fields = array_keys($pmpro_required_user_fields);
1700
- else
1701
- $required_fields = array();
1702
-
1703
- //required?
1704
- if(in_array($field, $required_fields))
1705
- {
1706
- $classes[] = "pmpro_required";
1707
- }
1708
-
1709
- $classes = apply_filters("pmpro_field_classes", $classes, $field);
1710
-
1711
- if(!empty($classes))
1712
- return implode(" ", $classes);
1713
- else
1714
- return "";
1715
- }
1716
-
1717
- //get a var from $_GET or $_POST
1718
- function pmpro_getParam($index, $method = "REQUEST", $default = "")
1719
- {
1720
- if($method == "REQUEST")
1721
- {
1722
- if(!empty($_REQUEST[$index]))
1723
- return $_REQUEST[$index];
1724
- }
1725
- elseif($method == "POST")
1726
- {
1727
- if(!empty($_POST[$index]))
1728
- return $_POST[$index];
1729
- }
1730
- elseif($method == "GET")
1731
- {
1732
- if(!empty($_GET[$index]))
1733
- return $_GET[$index];
1734
- }
1735
-
1736
- return $default;
1737
- }
1738
-
1739
- /*
1740
- Format an address from address, city, state, zip, country, and phone
1741
- */
1742
- function pmpro_formatAddress($name, $address1, $address2, $city, $state, $zip, $country, $phone, $nl2br = true)
1743
- {
1744
- $address = "";
1745
-
1746
- if(!empty($name))
1747
- $address .= $name . "\n";
1748
-
1749
- if(!empty($address1))
1750
- $address .= $address1 . "\n";
1751
-
1752
- if(!empty($address2))
1753
- $address .= $address2 . "\n";
1754
-
1755
- if(!empty($city) && !empty($state))
1756
- {
1757
- $address .= $city . ", " . $state;
1758
-
1759
- if(!empty($zip))
1760
- $address .= " " . $zip;
1761
-
1762
- $address .= "\n";
1763
- }
1764
-
1765
- if(!empty($country))
1766
- $address .= $country . "\n";
1767
-
1768
- if(!empty($phone))
1769
- $address .= formatPhone($phone);
1770
-
1771
- if($nl2br)
1772
- $address = nl2br($address);
1773
-
1774
- return $address;
1775
- }
1776
-
1777
- /*
1778
- Checks if all required settings are set.
1779
- */
1780
- function pmpro_is_ready()
1781
- {
1782
- global $wpdb, $pmpro_pages, $pmpro_level_ready, $pmpro_gateway_ready, $pmpro_pages_ready;
1783
-
1784
- //check if there is at least one level
1785
- $pmpro_level_ready = (bool)$wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_levels LIMIT 1");
1786
-
1787
- //check if the gateway settings are good. first check if it's needed (is there paid membership level)
1788
- $paid_membership_level = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_levels WHERE allow_signups = 1 AND (initial_payment > 0 OR billing_amount > 0 OR trial_amount > 0) LIMIT 1");
1789
- $paid_user_subscription = $wpdb->get_var("SELECT user_id FROM $wpdb->pmpro_memberships_users WHERE initial_payment > 0 OR billing_amount > 0 OR trial_amount > 0 LIMIT 1");
1790
-
1791
- if(empty($paid_membership_level) && empty($paid_user_subscription))
1792
- {
1793
- //no paid membership level now or attached to a user. we don't need the gateway setup
1794
- $pmpro_gateway_ready = true;
1795
- }
1796
- else
1797
- {
1798
- $gateway = pmpro_getOption("gateway");
1799
- if($gateway == "authorizenet")
1800
- {
1801
- if(pmpro_getOption("gateway_environment") && pmpro_getOption("loginname") && pmpro_getOption("transactionkey"))
1802
- $pmpro_gateway_ready = true;
1803
- else
1804
- $pmpro_gateway_ready = false;
1805
- }
1806
- elseif($gateway == "paypal" || $gateway == "paypalexpress")
1807
- {
1808
- if(pmpro_getOption("gateway_environment") && pmpro_getOption("gateway_email") && pmpro_getOption("apiusername") && pmpro_getOption("apipassword") && pmpro_getOption("apisignature"))
1809
- $pmpro_gateway_ready = true;
1810
- else
1811
- $pmpro_gateway_ready = false;
1812
- }
1813
- elseif($gateway == "paypalstandard")
1814
- {
1815
- if(pmpro_getOption("gateway_environment") && pmpro_getOption("gateway_email"))
1816
- $pmpro_gateway_ready = true;
1817
- else
1818
- $pmpro_gateway_ready = false;
1819
- }
1820
- elseif($gateway == "payflowpro")
1821
- {
1822
- if(pmpro_getOption("payflow_partner") && pmpro_getOption("payflow_vendor") && pmpro_getOption("payflow_user") && pmpro_getOption("payflow_pwd"))
1823
- $pmpro_gateway_ready = true;
1824
- else
1825
- $pmpro_gateway_ready = false;
1826
- }
1827
- elseif($gateway == "stripe")
1828
- {
1829
- if(pmpro_getOption("gateway_environment") && pmpro_getOption("stripe_secretkey") && pmpro_getOption("stripe_publishablekey"))
1830
- $pmpro_gateway_ready = true;
1831
- else
1832
- $pmpro_gateway_ready = false;
1833
- }
1834
- elseif($gateway == "braintree")
1835
- {
1836
- if(pmpro_getOption("gateway_environment") && pmpro_getOption("braintree_merchantid") && pmpro_getOption("braintree_publickey") && pmpro_getOption("braintree_privatekey"))
1837
- $pmpro_gateway_ready = true;
1838
- else
1839
- $pmpro_gateway_ready = false;
1840
- }
1841
- elseif($gateway == "twocheckout")
1842
- {
1843
- if(pmpro_getOption("gateway_environment") && pmpro_getOption("twocheckout_apiusername") && pmpro_getOption("twocheckout_apipassword"))
1844
- $pmpro_gateway_ready = true;
1845
- else
1846
- $pmpro_gateway_ready = false;
1847
- }
1848
- elseif($gateway == "cybersource")
1849
- {
1850
- if(pmpro_getOption("gateway_environment") && pmpro_getOption("cybersource_merchantid") && pmpro_getOption("cybersource_securitykey"))
1851
- $pmpro_gateway_ready = true;
1852
- else
1853
- $pmpro_gateway_ready = false;
1854
- }
1855
- elseif($gateway == "check")
1856
- {
1857
- $pmpro_gateway_ready = true;
1858
- }
1859
- else
1860
- {
1861
- $pmpro_gateway_ready = false;
1862
- }
1863
- }
1864
-
1865
- //check if we have all pages
1866
- if($pmpro_pages["account"] &&
1867
- $pmpro_pages["billing"] &&
1868
- $pmpro_pages["cancel"] &&
1869
- $pmpro_pages["checkout"] &&
1870
- $pmpro_pages["confirmation"] &&
1871
- $pmpro_pages["invoice"] &&
1872
- $pmpro_pages["levels"])
1873
- $pmpro_pages_ready = true;
1874
- else
1875
- $pmpro_pages_ready = false;
1876
-
1877
- //now check both
1878
- if($pmpro_gateway_ready && $pmpro_pages_ready)
1879
- $r = true;
1880
- else
1881
- $r = false;
1882
-
1883
- /**
1884
- * Filter to determine if PMPro setup is complete or
1885
- * if notices or warnings need to be shown in the PMPro settings.
1886
- *
1887
- * Note: The filter should return true or false and also set
1888
- * the $pmpro_level_ready, $pmpro_gateway_ready, $pmpro_pages_ready global variabls.
1889
- *
1890
- * @since 1.8.4.5
1891
- *
1892
- * @param bool $r ready?
1893
- */
1894
- $r = apply_filters('pmpro_is_ready', $r);
1895
-
1896
- return $r;
1897
- }
1898
-
1899
- /**
1900
- * Format a price per the currency settings.
1901
- *
1902
- * @since 1.7.15
1903
- */
1904
- function pmpro_formatPrice($price)
1905
- {
1906
- global $pmpro_currency, $pmpro_currency_symbol, $pmpro_currencies;
1907
-
1908
- //start with the price formatted with two decimals
1909
- $formatted = number_format($price, 2);
1910
-
1911
- //settings stored in array?
1912
- if(!empty($pmpro_currencies[$pmpro_currency]) && is_array($pmpro_currencies[$pmpro_currency]))
1913
- {
1914
- //format number do decimals, with decimal_separator and thousands_separator
1915
- $formatted = number_format($price,
1916
- (isset($pmpro_currencies[$pmpro_currency]['decimals']) ? (int)$pmpro_currencies[$pmpro_currency]['decimals'] : 2),
1917
- (isset($pmpro_currencies[$pmpro_currency]['decimal_separator']) ? $pmpro_currencies[$pmpro_currency]['decimal_separator'] : '.'),
1918
- (isset($pmpro_currencies[$pmpro_currency]['thousands_separator']) ? $pmpro_currencies[$pmpro_currency]['thousands_separator'] : ',')
1919
- );
1920
-
1921
- //which side is the symbol on?
1922
- if(!empty($pmpro_currencies[$pmpro_currency]['position']) && $pmpro_currencies[$pmpro_currency]['position']== 'left')
1923
- $formatted = $pmpro_currency_symbol . $formatted;
1924
- else
1925
- $formatted = $formatted . $pmpro_currency_symbol;
1926
- }
1927
- else
1928
- $formatted = $pmpro_currency_symbol . $formatted; //default to symbol on the left
1929
-
1930
- //filter
1931
- return apply_filters('pmpro_format_price', $formatted, $price, $pmpro_currency, $pmpro_currency_symbol);
1932
- }
1933
-
1934
- /**
1935
- * Which side does the currency symbol go on?
1936
- *
1937
- * @since 1.7.15
1938
- */
1939
- function pmpro_getCurrencyPosition()
1940
- {
1941
- global $pmpro_currency, $pmpro_currencies;
1942
-
1943
- if(!empty($pmpro_currencies[$pmpro_currency]) && is_array($pmpro_currencies[$pmpro_currency]) && !empty($pmpro_currencies[$pmpro_currency]['position']))
1944
- return $pmpro_currencies[$pmpro_currency]['position'];
1945
- else
1946
- return "left";
1947
- }
1948
-
1949
- /*
1950
- * What gateway should we be using?
1951
- *
1952
- * @since 1.8
1953
- */
1954
- function pmpro_getGateway()
1955
- {
1956
- //grab from param or options
1957
- if (!empty($_REQUEST['gateway']))
1958
- $gateway = $_REQUEST['gateway']; //gateway passed as param
1959
- elseif (!empty($_REQUEST['review']))
1960
- $gateway = "paypalexpress"; //if review param assume paypalexpress
1961
- else
1962
- $gateway = pmpro_getOption("gateway"); //get from options
1963
-
1964
- //set valid gateways - the active gateway in the settings and any gateway added through the filter will be allowed
1965
- if(pmpro_getOption("gateway", true) == "paypal")
1966
- $valid_gateways = apply_filters("pmpro_valid_gateways", array("paypal", "paypalexpress"));
1967
- else
1968
- $valid_gateways = apply_filters("pmpro_valid_gateways", array(pmpro_getOption("gateway", true)));
1969
-
1970
- //make sure it's valid
1971
- if(!in_array($gateway, $valid_gateways))
1972
- $gateway = false;
1973
-
1974
- //filter for good measure
1975
- $gateway = apply_filters('pmpro_get_gateway', $gateway, $valid_gateways);
1976
-
1977
- return $gateway;
1978
- }
1979
-
1980
- /*
1981
- * Does the date provided fall in this month.
1982
- * Used in logins/visits/views report.
1983
- *
1984
- * @since 1.8.3
1985
- */
1986
- function pmpro_isDateThisMonth($str)
1987
- {
1988
- $now = current_time('timestamp');
1989
- $this_month = intval(date("n", $now));
1990
- $this_year = intval(date("Y", $now));
1991
-
1992
- $date = strtotime($str, $now);
1993
- $date_month = intval(date("n", $date));
1994
- $date_year = intval(date("Y", $date));
1995
-
1996
- if($date_month === $this_month && $date_year === $this_year)
1997
- return true;
1998
- else
1999
- return false;
2000
- }
2001
-
2002
- /**
2003
- * Function to generate PMPro front end pages.
2004
- *
2005
- * @param array $pages {
2006
- * Formatted as array($name => $title) or array(array('title'=>'The Title', 'content'=>'The Content'))
2007
- *
2008
- * @type string $name Page name. (Letters, numbers, and underscores only.)
2009
- * @type string $title Page title.
2010
- * }
2011
- * @return array $created_pages Created page IDs.
2012
- * @since 1.8.5
2013
- */
2014
- function pmpro_generatePages($pages) {
2015
-
2016
- global $pmpro_pages;
2017
-
2018
- $pages_created = array();
2019
-
2020
- if(!empty($pages)) {
2021
- foreach($pages as $name => $page) {
2022
-
2023
- //does it already exist?
2024
- if(!empty($pmpro_pages[$name]))
2025
- continue;
2026
-
2027
- //no id set. create an array to store the page info
2028
- if(is_array($page)) {
2029
- $title = $page['title'];
2030
- $content = $page['content'];
2031
- } else {
2032
- $title = $page;
2033
- $content = '[pmpro_' . $name . ']';
2034
- }
2035
-
2036
- $insert = array(
2037
- 'post_title' => $title,
2038
- 'post_status' => 'publish',
2039
- 'post_type' => 'page',
2040
- 'post_content' => $content,
2041
- 'comment_status' => 'closed',
2042
- 'ping_status' => 'closed'
2043
- );
2044
-
2045
- //make non-account pages a subpage of account
2046
- if ($name != "account") {
2047
- $insert['post_parent'] = $pmpro_pages['account'];
2048
- }
2049
-
2050
- //create the page
2051
- $pmpro_pages[$name] = wp_insert_post($insert);
2052
-
2053
- //update the option too
2054
- pmpro_setOption($name . "_page_id", $pmpro_pages[$name]);
2055
- $pages_created[] = $pmpro_pages[$name];
2056
- }
2057
- }
2058
-
2059
- return $pages_created;
2060
- }
2061
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /****************************************************************
3
+
4
+ IMPORTANT. PLEASE READ.
5
+
6
+ DO NOT EDIT THIS FILE or any other file in the /wp-content/plugins/paid-memberships-pro/ directory.
7
+ Doing so could break the PMPro plugin and/or keep you from upgrading this plugin in the future.
8
+ We regularly release updates to the plugin, including important security fixes and new features.
9
+ You want to be able to upgrade.
10
+
11
+ If you were asked to insert code into "your functions.php file", it was meant that you edit the functions.php
12
+ in the root folder of your active theme. e.g. /wp-content/themes/twentytwelve/functions.php
13
+ You can also create a custom plugin to place customization code into. Instructions are here:
14
+ http://www.paidmembershipspro.com/2012/08/create-a-plugin-for-pmpro-customizations/
15
+
16
+ Further documentation for customizing Paid Memberships Pro can be found here:
17
+ http://www.paidmembershipspro.com/documentation/
18
+
19
+ ****************************************************************/
20
+ if(!function_exists("sornot"))
21
+ {
22
+ function sornot($t, $n)
23
+ {
24
+ if($n == 1)
25
+ return $t;
26
+ else
27
+ return $t . "s";
28
+ }
29
+ }
30
+
31
+ //set up wpdb for the tables we need
32
+ function pmpro_setDBTables()
33
+ {
34
+ global $wpdb;
35
+ $wpdb->hide_errors();
36
+ $wpdb->pmpro_membership_levels = $wpdb->prefix . 'pmpro_membership_levels';
37
+ $wpdb->pmpro_memberships_users = $wpdb->prefix . 'pmpro_memberships_users';
38
+ $wpdb->pmpro_memberships_categories = $wpdb->prefix . 'pmpro_memberships_categories';
39
+ $wpdb->pmpro_memberships_pages = $wpdb->prefix . 'pmpro_memberships_pages';
40
+ $wpdb->pmpro_membership_orders = $wpdb->prefix . 'pmpro_membership_orders';
41
+ $wpdb->pmpro_discount_codes = $wpdb->prefix . 'pmpro_discount_codes';
42
+ $wpdb->pmpro_discount_codes_levels = $wpdb->prefix . 'pmpro_discount_codes_levels';
43
+ $wpdb->pmpro_discount_codes_uses = $wpdb->prefix . 'pmpro_discount_codes_uses';
44
+ }
45
+ pmpro_setDBTables();
46
+
47
+ //from: http://stackoverflow.com/questions/5266945/wordpress-how-detect-if-current-page-is-the-login-page/5892694#5892694
48
+ function pmpro_is_login_page() {
49
+ return (in_array($GLOBALS['pagenow'], array('wp-login.php', 'wp-register.php')) || is_page("login"));
50
+ }
51
+
52
+ //thanks: http://wordpress.org/support/topic/is_plugin_active
53
+ function pmpro_is_plugin_active( $plugin ) {
54
+ return in_array( $plugin, (array) get_option( 'active_plugins', array() ) );
55
+ }
56
+
57
+ //scraping - override n if you have more than 1 group of matches and don't want the first group
58
+ function pmpro_getMatches($p, $s, $firstvalue = FALSE, $n = 1)
59
+ {
60
+ $ok = preg_match_all($p, $s, $matches);
61
+
62
+ if(!$ok)
63
+ return false;
64
+ else
65
+ {
66
+ if($firstvalue)
67
+ return $matches[$n][0];
68
+ else
69
+ return $matches[$n];
70
+ }
71
+ }
72
+
73
+ function pmpro_br2nl($text, $tags = "br")
74
+ {
75
+ if(!is_array($tags))
76
+ $tags = explode(" ", $tags);
77
+
78
+ foreach($tags as $tag)
79
+ {
80
+ $text = eregi_replace("<" . $tag . "[^>]*>", "\n", $text);
81
+ $text = eregi_replace("</" . $tag . "[^>]*>", "\n", $text);
82
+ }
83
+
84
+ return($text);
85
+ }
86
+
87
+ function pmpro_getOption($s, $force = false)
88
+ {
89
+ if(get_option("pmpro_" . $s))
90
+ return get_option("pmpro_" . $s);
91
+ else
92
+ return "";
93
+ }
94
+
95
+ function pmpro_setOption($s, $v = NULL)
96
+ {
97
+ //no value is given, set v to the p var
98
+ if($v === NULL && isset($_POST[$s]))
99
+ $v = $_POST[$s];
100
+
101
+ if(is_array($v))
102
+ $v = implode(",", $v);
103
+ else
104
+ $v = trim($v);
105
+
106
+ return update_option("pmpro_" . $s, $v);
107
+ }
108
+
109
+ function pmpro_get_slug($post_id)
110
+ {
111
+ global $pmpro_slugs, $wpdb;
112
+
113
+ //make sure post id is int for security
114
+ $post_id = intval($post_id);
115
+
116
+ if(!$pmpro_slugs[$post_id])
117
+ $pmpro_slugs[$post_id] = $wpdb->get_var("SELECT post_name FROM $wpdb->posts WHERE ID = '" . $post_id . "' LIMIT 1");
118
+
119
+ return $pmpro_slugs[$post_id];
120
+ }
121
+
122
+ function pmpro_url($page = NULL, $querystring = "", $scheme = NULL)
123
+ {
124
+ global $besecure;
125
+ $besecure = apply_filters("besecure", $besecure);
126
+
127
+ if(!$scheme && $besecure)
128
+ $scheme = "https";
129
+ elseif(!$scheme)
130
+ $scheme = "http";
131
+
132
+ if(!$page)
133
+ $page = "levels";
134
+
135
+ global $pmpro_pages;
136
+
137
+ //start with the permalink
138
+ $url = get_permalink($pmpro_pages[$page]);
139
+
140
+ //WPML/etc support
141
+ if(function_exists("icl_object_id") && defined("ICL_LANGUAGE_CODE"))
142
+ {
143
+ $trans_id = icl_object_id($pmpro_pages[$page], "page", false, ICL_LANGUAGE_CODE);
144
+ if(!empty($trans_id))
145
+ {
146
+ $url = get_permalink($trans_id);
147
+ }
148
+ }
149
+
150
+ //figure out querystring
151
+ if(strpos($url, "?"))
152
+ $querystring = str_replace("?", "&", $querystring);
153
+ $url .= $querystring;
154
+
155
+ //figure out scheme
156
+ if(is_ssl())
157
+ $url = str_replace("http:", "https:", $url);
158
+
159
+ return $url;
160
+ }
161
+
162
+ function pmpro_isLevelFree(&$level)
163
+ {
164
+ if(!empty($level) && $level->initial_payment <= 0 && $level->billing_amount <= 0 && $level->trial_amount <= 0)
165
+ return true;
166
+ else
167
+ return false;
168
+ }
169
+
170
+ function pmpro_isLevelRecurring(&$level)
171
+ {
172
+ if(!empty($level) && ($level->billing_amount > 0 || $level->trial_amount > 0))
173
+ return true;
174
+ else
175
+ return false;
176
+ }
177
+
178
+ function pmpro_isLevelTrial(&$level)
179
+ {
180
+ if($level->trial_limit > 0)
181
+ {
182
+ return true;
183
+ }
184
+ else
185
+ return false;
186
+ }
187
+
188
+ function pmpro_isLevelExpiring(&$level)
189
+ {
190
+ if($level->expiration_number > 0)
191
+ return true;
192
+ else
193
+ return false;
194
+ }
195
+
196
+ function pmpro_getLevelCost(&$level, $tags = true, $short = false)
197
+ {
198
+ //initial payment
199
+ if(!$short)
200
+ $r = sprintf(__('The price for membership is <strong>%s</strong> now', 'pmpro'), pmpro_formatPrice($level->initial_payment));
201
+ else
202
+ $r = sprintf(__('<strong>%s</strong> now', 'pmpro'), pmpro_formatPrice($level->initial_payment));
203
+
204
+ //recurring part
205
+ if($level->billing_amount != '0.00')
206
+ {
207
+ if($level->billing_limit > 1)
208
+ {
209
+ if($level->cycle_number == '1')
210
+ {
211
+ $r .= sprintf(__(' and then <strong>%s per %s for %d more %s</strong>.', 'pmpro'), pmpro_formatPrice($level->billing_amount), pmpro_translate_billing_period($level->cycle_period), $level->billing_limit, pmpro_translate_billing_period($level->cycle_period, $level->billing_limit));
212
+ }
213
+ else
214
+ {
215
+ $r .= sprintf(__(' and then <strong>%s every %d %s for %d more %s</strong>.', 'pmpro'), pmpro_formatPrice($level->billing_amount), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number), $level->billing_limit, pmpro_translate_billing_period($level->cycle_period, $level->billing_limit));
216
+ }
217
+ }
218
+ elseif($level->billing_limit == 1)
219
+ {
220
+ $r .= sprintf(__(' and then <strong>%s after %d %s</strong>.', 'pmpro'), pmpro_formatPrice($level->billing_amount), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number));
221
+ }
222
+ else
223
+ {
224
+ if( $level->billing_amount === $level->initial_payment ) {
225
+ if($level->cycle_number == '1')
226
+ {
227
+ if(!$short)
228
+ $r = sprintf(__('The price for membership is <strong>%s per %s</strong>.', 'pmpro'), pmpro_formatPrice($level->initial_payment), pmpro_translate_billing_period($level->cycle_period) );
229
+ else
230
+ $r = sprintf(__('<strong>%s per %s</strong>.', 'pmpro'), pmpro_formatPrice($level->initial_payment), pmpro_translate_billing_period($level->cycle_period) );
231
+ }
232
+ else
233
+ {
234
+ if(!$short)
235
+ $r = sprintf(__('The price for membership is <strong>%s every %d %s</strong>.', 'pmpro'), pmpro_formatPrice($level->initial_payment), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number) );
236
+ else
237
+ $r = sprintf(__('<strong>%s every %d %s</strong>.', 'pmpro'), pmpro_formatPrice($level->initial_payment), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number) );
238
+ }
239
+ } else {
240
+ if($level->cycle_number == '1')
241
+ {
242
+ $r .= sprintf(__(' and then <strong>%s per %s</strong>.', 'pmpro'), pmpro_formatPrice($level->billing_amount), pmpro_translate_billing_period($level->cycle_period));
243
+ }
244
+ else
245
+ {
246
+ $r .= sprintf(__(' and then <strong>%s every %d %s</strong>.', 'pmpro'), pmpro_formatPrice($level->billing_amount), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number));
247
+ }
248
+ }
249
+ }
250
+ }
251
+ else
252
+ $r .= '.';
253
+
254
+ //add a space
255
+ $r .= ' ';
256
+
257
+ //trial part
258
+ if($level->trial_limit)
259
+ {
260
+ if($level->trial_amount == '0.00')
261
+ {
262
+ if($level->trial_limit == '1')
263
+ {
264
+ $r .= ' ' . __('After your initial payment, your first payment is Free.', 'pmpro');
265
+ }
266
+ else
267
+ {
268
+ $r .= ' ' . sprintf(__('After your initial payment, your first %d payments are Free.', 'pmpro'), $level->trial_limit);
269
+ }
270
+ }
271
+ else
272
+ {
273
+ if($level->trial_limit == '1')
274
+ {
275
+ $r .= ' ' . sprintf(__('After your initial payment, your first payment will cost %s.', 'pmpro'), pmpro_formatPrice($level->trial_amount));
276
+ }
277
+ else
278
+ {
279
+ $r .= ' ' . sprintf(__('After your initial payment, your first %d payments will cost %s.', 'pmpro'), $level->trial_limit, pmpro_formatPrice($level->trial_amount));
280
+ }
281
+ }
282
+ }
283
+
284
+ //taxes part
285
+ $tax_state = pmpro_getOption("tax_state");
286
+ $tax_rate = pmpro_getOption("tax_rate");
287
+
288
+ if($tax_state && $tax_rate && !pmpro_isLevelFree($level))
289
+ {
290
+ $r .= sprintf(__('Customers in %s will be charged %s%% tax.', 'pmpro'), $tax_state, round($tax_rate * 100, 2));
291
+ }
292
+
293
+ if(!$tags)
294
+ $r = strip_tags($r);
295
+
296
+ $r = apply_filters("pmpro_level_cost_text", $r, $level, $tags, $short); //passing $tags and $short since v1.8
297
+ return $r;
298
+ }
299
+
300
+ function pmpro_getLevelExpiration(&$level)
301
+ {
302
+ if($level->expiration_number)
303
+ {
304
+ $expiration_text = sprintf(__("Membership expires after %d %s.", "pmpro"), $level->expiration_number, pmpro_translate_billing_period($level->expiration_period, $level->expiration_number));
305
+ }
306
+ else
307
+ $expiration_text = "";
308
+
309
+ $expiration_text = apply_filters("pmpro_level_expiration_text", $expiration_text, $level);
310
+ return $expiration_text;
311
+ }
312
+
313
+ function pmpro_hideAds()
314
+ {
315
+ global $pmpro_display_ads;
316
+ return !$pmpro_display_ads;
317
+ }
318
+
319
+ function pmpro_displayAds()
320
+ {
321
+ global $pmpro_display_ads;
322
+ return $pmpro_display_ads;
323
+ }
324
+
325
+ function pmpro_next_payment($user_id = NULL, $order_status = "success", $format = "timestamp")
326
+ {
327
+ global $wpdb, $current_user;
328
+ if(!$user_id)
329
+ $user_id = $current_user->ID;
330
+
331
+ if(!$user_id)
332
+ $r = false;
333
+ else
334
+ {
335
+ //get last order
336
+ $order = new MemberOrder();
337
+ $order->getLastMemberOrder($user_id, $order_status);
338
+
339
+ //get current membership level
340
+ $level = pmpro_getMembershipLevelForUser($user_id);
341
+
342
+ if(!empty($order) && !empty($order->id) && !empty($level) && !empty($level->id) && !empty($level->cycle_number))
343
+ {
344
+ //last payment date
345
+ $lastdate = date("Y-m-d", $order->timestamp);
346
+
347
+ //next payment date
348
+ $nextdate = $wpdb->get_var("SELECT UNIX_TIMESTAMP('" . $lastdate . "' + INTERVAL " . $level->cycle_number . " " . $level->cycle_period . ")");
349
+
350
+ $r = $nextdate;
351
+ }
352
+ else
353
+ {
354
+ //no order or level found, or level was not recurring
355
+ $r = false;
356
+ }
357
+ }
358
+
359
+ /**
360
+ * Filter the next payment date.
361
+ *
362
+ * @since 1.8.5
363
+ *
364
+ * @param mixed $r false or the next payment date timestamp
365
+ * @param int $user_id The user id to get the next payment date for
366
+ * @param string $order_status Status or array of statuses to find the last order based on.
367
+ */
368
+ $r = apply_filters('pmpro_next_payment', $r, $user_id, $order_status);
369
+
370
+ //return in desired format
371
+ if($r === false)
372
+ return false; //always return false when no date found
373
+ elseif($format == "timestamp")
374
+ return $r;
375
+ elseif($format == "date_format")
376
+ return date(get_option('date_format'), $r);
377
+ else
378
+ return date($format, $r); //assume a PHP date format
379
+ }
380
+
381
+ if(!function_exists("last4"))
382
+ {
383
+ function last4($t)
384
+ {
385
+ return substr($t, strlen($t) - 4, 4);
386
+ }
387
+ }
388
+
389
+ if(!function_exists("hideCardNumber"))
390
+ {
391
+ function hideCardNumber($c, $dashes = true)
392
+ {
393
+ if($c)
394
+ {
395
+ if($dashes)
396
+ return "XXXX-XXXX-XXXX-" . substr($c, strlen($c) - 4, 4);
397
+ else
398
+ return "XXXXXXXXXXXX" . substr($c, strlen($c) - 4, 4);
399
+ }
400
+ else
401
+ {
402
+ return "";
403
+ }
404
+ }
405
+ }
406
+
407
+ //check for existing functions since we didn't use a prefix for this function
408
+ if(!function_exists("cleanPhone"))
409
+ {
410
+ /**
411
+ * Function to remove special characters from a phone number.
412
+ * NOTE: Could probably replace with preg_replace("[^0-9]", "", $phone)
413
+ *
414
+ * @since 1.0
415
+ *
416
+ * @param string $phone The phone number to clean.
417
+ */
418
+ function cleanPhone($phone)
419
+ {
420
+ //if a + is passed, just pass it along
421
+ if(strpos($phone, "+") !== false)
422
+ return $phone;
423
+ //clean the phone
424
+ $phone = str_replace("-", "", $phone);
425
+ $phone = str_replace(".", "", $phone);
426
+ $phone = str_replace("(", "", $phone);
427
+ $phone = str_replace(")", "", $phone);
428
+ $phone = str_replace(" ", "", $phone);
429
+ return $phone;
430
+ }
431
+ }
432
+
433
+ //check for existing functions since we didn't use a prefix for this function
434
+ if(!function_exists("formatPhone"))
435
+ {
436
+ /**
437
+ * Function to format a phone number.
438
+ *
439
+ * @since 1.0
440
+ *
441
+ * @param string $phone The phone number to format.
442
+ */
443
+ function formatPhone($phone)
444
+ {
445
+ $r = cleanPhone($phone);
446
+
447
+ if(strlen($r) == 11)
448
+ $r = substr($r, 0, 1) . " (" . substr($r, 1, 3) . ") " . substr($r, 4, 3) . "-" . substr($r, 7, 4);
449
+ elseif(strlen($r) == 10)
450
+ $r = "(" . substr($r, 0, 3) . ") " . substr($r, 3, 3) . "-" . substr($r, 6, 4);
451
+ elseif(strlen($r) == 7)
452
+ $r = substr($r, 0, 3) . "-" . substr($r, 3, 4);
453
+
454
+ /**
455
+ * Filter to do more or less cleaning of phone numbers.
456
+ *
457
+ * @since 1.8.4.4
458
+ *
459
+ * @param string $r The formatted phone number.
460
+ * @param string $phone The original phone number.
461
+ */
462
+ return apply_filters('pmpro_format_phone', $r, $phone);
463
+ }
464
+ }
465
+
466
+ function pmpro_showRequiresMembershipMessage()
467
+ {
468
+ //TODO $current_user $post_membership_levels_names are undefined variables
469
+ //get the correct message
470
+ if(is_feed())
471
+ {
472
+ $content = pmpro_getOption("rsstext");
473
+ $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content);
474
+ }
475
+ elseif($current_user->ID)
476
+ {
477
+ //not a member
478
+ $content = pmpro_getOption("nonmembertext");
479
+ $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content);
480
+ }
481
+ else
482
+ {
483
+ //not logged in!
484
+ $content = pmpro_getOption("notloggedintext");
485
+ $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content);
486
+ }
487
+ }
488
+
489
+ /**
490
+ * Function to check if a user has specified membership levels.
491
+ *
492
+ * pmpro_hasMembershipLevel() checks if the passed user is a member of the passed level
493
+ * $level may either be the ID or name of the desired membership_level. (or an array of such)
494
+ * If $user_id is omitted, the value will be retrieved from $current_user.
495
+ *
496
+ * Return values:
497
+ * * Success returns boolean true.
498
+ * * Failure returns a string containing the error message.
499
+ *
500
+ * @since 1.8.5 Added 'e' option for expired members.
501
+ * @since 1.0.0
502
+ *
503
+ * @param mixed $levels The levels to check.
504
+ * @param int $user_id The user ID to check.
505
+ *
506
+ * @return bool Result of membership query.
507
+ */
508
+ function pmpro_hasMembershipLevel($levels = NULL, $user_id = NULL)
509
+ {
510
+ global $current_user, $wpdb;
511
+
512
+ $return = false;
513
+
514
+ if(empty($user_id)) //no user_id passed, check the current user
515
+ {
516
+ $user_id = $current_user->ID;
517
+ $membership_levels = $current_user->membership_levels;
518
+ }
519
+ elseif(is_numeric($user_id)) //get membership levels for given user
520
+ {
521
+ $membership_levels = pmpro_getMembershipLevelsForUser($user_id);
522
+ }
523
+ else
524
+ return false; //invalid user_id
525
+
526
+ if($levels === "0" || $levels === 0) //if 0 was passed, return true if they have no level and false if they have any
527
+ {
528
+ $return = empty($membership_levels);
529
+ }
530
+ elseif(empty($levels)) //if no level var was passed, we're just checking if they have any level
531
+ {
532
+ $return = !empty($membership_levels);
533
+ }
534
+ else
535
+ {
536
+ if(!is_array($levels)) //make an array out of a single element so we can use the same code
537
+ {
538
+ $levels = array($levels);
539
+ }
540
+
541
+ if(empty($membership_levels))
542
+ {
543
+ //user has no levels just check if 0, L, -1, or e was sent in one of the levels
544
+ if(in_array(0, $levels, true) || in_array("0", $levels))
545
+ $return = true;
546
+ elseif(in_array("L", $levels) || in_array("l", $levels))
547
+ $return = (!empty($user_id) && $user_id == $current_user->ID);
548
+ elseif(in_array("-L", $levels) || in_array("-l", $levels))
549
+ $return = (empty($user_id) || $user_id != $current_user->ID);
550
+ elseif(in_array("E", $levels) || in_array("e", $levels)) {
551
+ $sql = "SELECT id FROM $wpdb->pmpro_memberships_users WHERE user_id=$user_id AND status='expired' LIMIT 1";
552
+ $expired = $wpdb->get_var($sql);
553
+ return !empty($expired);
554
+ }
555
+ }
556
+ else
557
+ {
558
+ foreach($levels as $level)
559
+ {
560
+ if(strtoupper($level) == "L")
561
+ {
562
+ //checking if user is logged in
563
+ if(!empty($user_id) && $user_id == $current_user->ID)
564
+ $return = true;
565
+ }
566
+ elseif(strtoupper($level) == "-L")
567
+ {
568
+ //checking if user is logged out
569
+ if(empty($user_id) || $user_id != $current_user->ID)
570
+ $return = true;
571
+ }
572
+ elseif($level == "0" || strtoupper($level) == "E")
573
+ {
574
+ continue; //user with levels so not a "non-member" or expired
575
+ }
576
+ else
577
+ {
578
+ //checking a level id
579
+ $level_obj = pmpro_getLevel(is_numeric($level) ? abs(intval($level)) : $level); //make sure our level is in a proper format
580
+ if(empty($level_obj)){continue;} //invalid level
581
+ $found_level = false;
582
+ foreach($membership_levels as $membership_level)
583
+ {
584
+ if($membership_level->id == $level_obj->id) //found a match
585
+ {
586
+ $found_level = true;
587
+ }
588
+ }
589
+
590
+ if(is_numeric($level) && intval($level) < 0 && !$found_level) //checking for the absence of this level and they don't have it
591
+ {
592
+ $return = true;
593
+ }
594
+ elseif(is_numeric($level) && intval($level) > 0 && $found_level) //checking for the presence of this level and they have it
595
+ {
596
+ $return = true;
597
+ }
598
+ elseif(!is_numeric($level)) //if a level name was passed
599
+ $return = $found_level;
600
+ }
601
+ }
602
+ }
603
+ }
604
+
605
+ $return = apply_filters("pmpro_has_membership_level", $return, $user_id, $levels);
606
+ return $return;
607
+ }
608
+
609
+ /* pmpro_changeMembershipLevel() creates or updates the membership level of the given user to the given level.
610
+ *
611
+ * $level may either be the ID or name of the desired membership_level.
612
+ * If $user_id is omitted, the value will be retrieved from $current_user.
613
+ *
614
+ * Return values:
615
+ * Success returns boolean true.
616
+ * Failure returns boolean false.
617
+ */
618
+ function pmpro_changeMembershipLevel($level, $user_id = NULL, $old_level_status = 'inactive')
619
+ {
620
+ global $wpdb;
621
+ global $current_user, $pmpro_error;
622
+
623
+ if(empty($user_id))
624
+ {
625
+ $user_id = $current_user->ID;
626
+ }
627
+
628
+ if(empty($user_id))
629
+ {
630
+ $pmpro_error = __("User ID not found.", "pmpro");
631
+ return false;
632
+ }
633
+
634
+ //make sure user id is int for security
635
+ $user_id = intval($user_id);
636
+
637
+ if(empty($level)) //cancelling membership
638
+ {
639
+ $level = 0;
640
+ }
641
+ else if(is_array($level))
642
+ {
643
+ //custom level
644
+ }
645
+ else
646
+ {
647
+ $level_obj = pmpro_getLevel($level);
648
+ if(empty($level_obj))
649
+ {
650
+ $pmpro_error = __("Invalid level.", "pmpro");
651
+ return false;
652
+ }
653
+ $level = $level_obj->id;
654
+ }
655
+
656
+ //if it's a custom level, they're changing
657
+ if(!is_array($level))
658
+ {
659
+ //are they even changing?
660
+ if(pmpro_hasMembershipLevel($level, $user_id)) {
661
+ $pmpro_error = __("not changing?", "pmpro");
662
+ return false; //not changing
663
+ }
664
+ }
665
+
666
+ //get all active membershipships for this user
667
+ $old_levels = pmpro_getMembershipLevelsForUser($user_id);
668
+
669
+ //deactivate old memberships based on the old_level_status passed in (updates pmpro_memberships_users table)
670
+ if($old_levels)
671
+ {
672
+ foreach($old_levels as $old_level) {
673
+
674
+ $sql = "UPDATE $wpdb->pmpro_memberships_users SET `status`='$old_level_status', `enddate`='" . current_time('mysql') . "' WHERE `id`=".$old_level->subscription_id;
675
+
676
+ if(!$wpdb->query($sql))
677
+ {
678
+ $pmpro_error = __("Error interacting with database", "pmpro") . ": ".(mysql_errno()?mysql_error():'unavailable');
679
+
680
+ return false;
681
+ }
682
+ }
683
+ }
684
+
685
+ //get level id
686
+ if(is_array($level))
687
+ $level_id = $level['membership_id']; //custom level
688
+ else
689
+ $level_id = $level; //just id
690
+
691
+ /**
692
+ * Action to run before the membership level changes.
693
+ *
694
+ * @param int $level_id ID of the level changed to.
695
+ * @param int $user_id ID of the user changed.
696
+ */
697
+ do_action("pmpro_before_change_membership_level", $level_id, $user_id);
698
+
699
+ //should we cancel their gateway subscriptions?
700
+ $pmpro_cancel_previous_subscriptions = true;
701
+ if(isset($_REQUEST['cancel_membership']) && $_REQUEST['cancel_membership'] == false)
702
+ $pmpro_cancel_previous_subscriptions = false;
703
+ $pmpro_cancel_previous_subscriptions = apply_filters("pmpro_cancel_previous_subscriptions", $pmpro_cancel_previous_subscriptions);
704
+
705
+ //cancel any other subscriptions they have (updates pmpro_membership_orders table)
706
+ if($pmpro_cancel_previous_subscriptions)
707
+ {
708
+ $other_order_ids = $wpdb->get_col("SELECT id FROM $wpdb->pmpro_membership_orders WHERE user_id = '" . $user_id . "' AND status = 'success' ORDER BY id DESC");
709
+
710
+ foreach($other_order_ids as $order_id)
711
+ {
712
+ $c_order = new MemberOrder($order_id);
713
+ $c_order->cancel();
714
+
715
+ if(!empty($c_order->error))
716
+ $pmpro_error = $c_order->error;
717
+ }
718
+ }
719
+
720
+ //insert current membership
721
+ if(!empty($level)) //are we getting a new one or just cancelling the old ones
722
+ {
723
+ if(is_array($level))
724
+ {
725
+ //make sure the dates are in good formats
726
+ if($level['startdate'] != current_time('mysql') && $level['startdate'] != "NULL" && substr($level['startdate'], 0, 1) != "'")
727
+ $level['startdate'] = "'" . $level['startdate'] . "'";
728
+
729
+ if($level['enddate'] != current_time('mysql') && $level['enddate'] != "NULL" && substr($level['enddate'], 0, 1) != "'")
730
+ $level['enddate'] = "'" . $level['enddate'] . "'";
731
+
732
+ //Better support mySQL Strict Mode by passing a proper enum value for cycle_period
733
+ if ($level['cycle_period'] == '') $level['cycle_period'] = 0;
734
+
735
+ $sql = "INSERT INTO $wpdb->pmpro_memberships_users (user_id, membership_id, code_id, initial_payment, billing_amount, cycle_number, cycle_period, billing_limit, trial_amount, trial_limit, startdate, enddate)
736
+ VALUES('" . $level['user_id'] . "',
737
+ '" . $level['membership_id'] . "',
738
+ '" . intval($level['code_id']) . "',
739
+ '" . $level['initial_payment'] . "',
740
+ '" . $level['billing_amount'] . "',
741
+ '" . $level['cycle_number'] . "',
742
+ '" . $level['cycle_period'] . "',
743
+ '" . $level['billing_limit'] . "',
744
+ '" . $level['trial_amount'] . "',
745
+ '" . $level['trial_limit'] . "',
746
+ " . $level['startdate'] . ",
747
+ " . $level['enddate'] . ")";
748
+
749
+ if(!$wpdb->query($sql))
750
+ {
751
+ $pmpro_error = __("Error interacting with database", "pmpro") . ": ".(mysql_errno()?mysql_error():'unavailable');
752
+ return false;
753
+ }
754
+ }
755
+ else
756
+ {
757
+ $sql = "INSERT INTO $wpdb->pmpro_memberships_users (user_id, membership_id, code_id, initial_payment, billing_amount, cycle_number, cycle_period, billing_limit, trial_amount, trial_limit, startdate, enddate)
758
+ VALUES (
759
+ '" . $user_id . "',
760
+ '" . $level . "',
761
+ '0',
762
+ '0',
763
+ '0',
764
+ '0',
765
+ '0',
766
+ '0',
767
+ '0',
768
+ '0',
769
+ '" . current_time('mysql') . "',
770
+ '0000-00-00 00:00:00'
771
+ )";
772
+
773
+ if(!$wpdb->query($sql))
774
+ {
775
+ $pmpro_error = __("Error interacting with database", "pmpro") . ": ".(mysql_errno()?mysql_error():'unavailable');
776
+ return false;
777
+ }
778
+ }
779
+ }
780
+
781
+ //remove cached level
782
+ global $all_membership_levels;
783
+ unset($all_membership_levels[$user_id]);
784
+
785
+ //update user data and call action
786
+ pmpro_set_current_user();
787
+
788
+ /**
789
+ * Action to run after the membership level changes.
790
+ *
791
+ * @param int $level_id ID of the level changed to.
792
+ * @param int $user_id ID of the user changed.
793
+ */
794
+ do_action("pmpro_after_change_membership_level", $level_id, $user_id);
795
+ return true;
796
+ }
797
+
798
+ /* pmpro_toggleMembershipCategory() creates or deletes a linking entry between the membership level and post category tables.
799
+ *
800
+ * $level may either be the ID or name of the desired membership_level.
801
+ * $category must be a valid post category ID.
802
+ *
803
+ * Return values:
804
+ * Success returns boolean true.
805
+ * Failure returns a string containing the error message.
806
+ */
807
+ function pmpro_toggleMembershipCategory( $level, $category, $value )
808
+ {
809
+ global $wpdb;
810
+ $category = intval($category);
811
+
812
+ if ( ($level = intval($level)) <= 0 )
813
+ {
814
+ $safe = addslashes($level);
815
+ if ( ($level = intval($wpdb->get_var("SELECT id FROM {$wpdb->pmpro_membership_levels} WHERE name = '$safe' LIMIT 1"))) <= 0 )
816
+ {
817
+ return __("Membership level not found.", "pmpro");
818
+ }
819
+ }
820
+
821
+ if ( $value )
822
+ {
823
+ $sql = "REPLACE INTO {$wpdb->pmpro_memberships_categories} (`membership_id`,`category_id`) VALUES ('$level','$category')";
824
+ $wpdb->query($sql);
825
+ if(mysql_errno()) return mysql_error();
826
+ }
827
+ else
828
+ {
829
+ $sql = "DELETE FROM {$wpdb->pmpro_memberships_categories} WHERE `membership_id` = '$level' AND `category_id` = '$category' LIMIT 1";
830
+ $wpdb->query($sql);
831
+ if(mysql_errno()) return mysql_error();
832
+ }
833
+
834
+ return true;
835
+ }
836
+
837
+ /* pmpro_updateMembershipCategories() ensures that all those and only those categories given
838
+ * are associated with the given membership level.
839
+ *
840
+ * $level is a valid membership level ID or name
841
+ * $categories is an array of post category IDs
842
+ *
843
+ * Return values:
844
+ * Success returns boolean true.
845
+ * Failure returns a string containing the error message.
846
+ */
847
+ function pmpro_updateMembershipCategories($level, $categories)
848
+ {
849
+ global $wpdb;
850
+
851
+ if(!is_numeric($level))
852
+ {
853
+ $level = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_levels WHERE name = '" . esc_sql($level) . "' LIMIT 1");
854
+ if(empty($level))
855
+ {
856
+ return __("Membership level not found.", "pmpro");
857
+ }
858
+ }
859
+
860
+ // remove all existing links...
861
+ $sqlQuery = "DELETE FROM $wpdb->pmpro_memberships_categories WHERE `membership_id` = '" . esc_sql($level) . "'";
862
+ $wpdb->query($sqlQuery);
863
+ if(mysql_errno()) return mysql_error();
864
+
865
+ // add the given links [back?] in...
866
+ foreach($categories as $cat)
867
+ {
868
+ if(is_string($r = pmpro_toggleMembershipCategory( $level, $cat, true)))
869
+ {
870
+ //uh oh, error
871
+ return $r;
872
+ }
873
+ }
874
+
875
+ //all good
876
+ return true;
877
+ }
878
+
879
+ /* pmpro_getMembershipCategories() returns the categories for a given level
880
+ *
881
+ * $level_id is a valid membership level ID
882
+ *
883
+ * Return values:
884
+ * Success returns boolean true.
885
+ * Failure returns boolean false.
886
+ */
887
+ function pmpro_getMembershipCategories($level_id)
888
+ {
889
+ $level_id = intval($level_id);
890
+
891
+ global $wpdb;
892
+ $categories = $wpdb->get_col("SELECT c.category_id
893
+ FROM {$wpdb->pmpro_memberships_categories} AS c
894
+ WHERE c.membership_id = '" . $level_id . "'");
895
+
896
+ return $categories;
897
+ }
898
+
899
+
900
+ function pmpro_isAdmin($user_id = NULL)
901
+ {
902
+ global $current_user, $wpdb;
903
+ if(!$user_id)
904
+ $user_id = $current_user->ID;
905
+
906
+ if(!$user_id)
907
+ return false;
908
+
909
+ $admincap = user_can($user_id, "manage_options");
910
+ if($admincap)
911
+ return true;
912
+ else
913
+ return false;
914
+ }
915
+
916
+ function pmpro_replaceUserMeta($user_id, $meta_keys, $meta_values, $prev_values = NULL)
917
+ {
918
+ //expects all arrays for last 3 params or all strings
919
+ if(!is_array($meta_keys))
920
+ {
921
+ $meta_keys = array($meta_keys);
922
+ $meta_values = array($meta_values);
923
+ $prev_values = array($prev_values);
924
+ }
925
+
926
+ for($i = 0; $i < count($meta_values); $i++)
927
+ {
928
+ if($prev_values[$i])
929
+ {
930
+ update_user_meta($user_id, $meta_keys[$i], $meta_values[$i], $prev_values[$i]);
931
+ }
932
+ else
933
+ {
934
+ $old_value = get_user_meta($user_id, $meta_keys[$i], true);
935
+ if($old_value)
936
+ {
937
+ update_user_meta($user_id, $meta_keys[$i], $meta_values[$i], $old_value);
938
+ }
939
+ else
940
+ {
941
+ update_user_meta($user_id, $meta_keys[$i], $meta_values[$i]);
942
+ }
943
+ }
944
+ }
945
+
946
+ return $i;
947
+ }
948
+
949
+ function pmpro_getMetavalues($query)
950
+ {
951
+ global $wpdb;
952
+
953
+ $results = $wpdb->get_results($query);
954
+ $r = new stdClass();
955
+ foreach($results as $result)
956
+ {
957
+ if(!empty($r))
958
+ $r->{$result->key} = $result->value;
959
+ }
960
+
961
+ return $r;
962
+ }
963
+
964
+ //function to return the pagination string
965
+ function pmpro_getPaginationString($page = 1, $totalitems, $limit = 15, $adjacents = 1, $targetpage = "/", $pagestring = "&pn=")
966
+ {
967
+ //defaults
968
+ if(!$adjacents) $adjacents = 1;
969
+ if(!$limit) $limit = 15;
970
+ if(!$page) $page = 1;
971
+ if(!$targetpage) $targetpage = "/";
972
+
973
+ //other vars
974
+ $prev = $page - 1; //previous page is page - 1
975
+ $next = $page + 1; //next page is page + 1
976
+ $lastpage = ceil($totalitems / $limit); //lastpage is = total items / items per page, rounded up.
977
+ $lpm1 = $lastpage - 1; //last page minus 1
978
+
979
+ /*
980
+ Now we apply our rules and draw the pagination object.
981
+ We're actually saving the code to a variable in case we want to draw it more than once.
982
+ */
983
+ $pagination = "";
984
+ if($lastpage > 1)
985
+ {
986
+ $pagination .= "<div class=\"pmpro_pagination\"";
987
+ if(!empty($margin) || !empty($padding))
988
+ {
989
+ $pagination .= " style=\"";
990
+ if($margin)
991
+ $pagination .= "margin: $margin;";
992
+ if($padding)
993
+ $pagination .= "padding: $padding;";
994
+ $pagination .= "\"";
995
+ }
996
+ $pagination .= ">";
997
+
998
+ //previous button
999
+ if ($page > 1)
1000
+ $pagination .= "<a href=\"$targetpage$pagestring$prev\">&laquo; prev</a>";
1001
+ else
1002
+ $pagination .= "<span class=\"disabled\">&laquo; prev</span>";
1003
+
1004
+ //pages
1005
+ if ($lastpage < 7 + ($adjacents * 2)) //not enough pages to bother breaking it up
1006
+ {
1007
+ for ($counter = 1; $counter <= $lastpage; $counter++)
1008
+ {
1009
+ if ($counter == $page)
1010
+ $pagination .= "<span class=\"current\">$counter</span>";
1011
+ else
1012
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
1013
+ }
1014
+ }
1015
+ elseif($lastpage >= 7 + ($adjacents * 2)) //enough pages to hide some
1016
+ {
1017
+ //close to beginning; only hide later pages
1018
+ if($page < 1 + ($adjacents * 3))
1019
+ {
1020
+ for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++)
1021
+ {
1022
+ if ($counter == $page)
1023
+ $pagination .= "<span class=\"current\">$counter</span>";
1024
+ else
1025
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
1026
+ }
1027
+ $pagination .= "...";
1028
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $lpm1 . "\">$lpm1</a>";
1029
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $lastpage . "\">$lastpage</a>";
1030
+ }
1031
+ //in middle; hide some front and some back
1032
+ elseif($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2))
1033
+ {
1034
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . "1\">1</a>";
1035
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . "2\">2</a>";
1036
+ $pagination .= "...";
1037
+ for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++)
1038
+ {
1039
+ if ($counter == $page)
1040
+ $pagination .= "<span class=\"current\">$counter</span>";
1041
+ else
1042
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
1043
+ }
1044
+ $pagination .= "...";
1045
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $lpm1 . "\">$lpm1</a>";
1046
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $lastpage . "\">$lastpage</a>";
1047
+ }
1048
+ //close to end; only hide early pages
1049
+ else
1050
+ {
1051
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . "1\">1</a>";
1052
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . "2\">2</a>";
1053
+ $pagination .= "...";
1054
+ for ($counter = $lastpage - (1 + ($adjacents * 3)); $counter <= $lastpage; $counter++)
1055
+ {
1056
+ if ($counter == $page)
1057
+ $pagination .= "<span class=\"current\">$counter</span>";
1058
+ else
1059
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
1060
+ }
1061
+ }
1062
+ }
1063
+
1064
+ //next button
1065
+ if ($page < $counter - 1)
1066
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $next . "\">next &raquo;</a>";
1067
+ else
1068
+ $pagination .= "<span class=\"disabled\">next &raquo;</span>";
1069
+ $pagination .= "</div>\n";
1070
+ }
1071
+
1072
+ return $pagination;
1073
+
1074
+ }
1075
+
1076
+ function pmpro_calculateInitialPaymentRevenue($s = NULL, $l = NULL)
1077
+ {
1078
+ global $wpdb;
1079
+
1080
+ //if we're limiting users by search
1081
+ if($s || $l)
1082
+ {
1083
+ $user_ids_query = "SELECT u.ID FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id WHERE mu.status = 'active' ";
1084
+ if($s)
1085
+ $user_ids_query .= "AND (u.user_login LIKE '%" . esc_sql($s) . "%' OR u.user_email LIKE '%" . esc_sql($s) . "%' OR um.meta_value LIKE '%$" . esc_sql(s) . "%') ";
1086
+ if($l)
1087
+ $user_ids_query .= "AND mu.membership_id = '" . esc_sql($l) . "' ";
1088
+ }
1089
+
1090
+ //query to sum initial payments
1091
+ $sqlQuery = "SELECT SUM(initial_payment) FROM $wpdb->pmpro_memberships_users WHERE `status` = 'active' ";
1092
+ if(!empty($user_ids_query))
1093
+ $sqlQuery .= "AND user_id IN(" . $user_ids_query . ") ";
1094
+
1095
+ $total = $wpdb->get_var($sqlQuery);
1096
+
1097
+ return (double)$total;
1098
+ }
1099
+
1100
+ function pmpro_calculateRecurringRevenue($s, $l)
1101
+ {
1102
+ global $wpdb;
1103
+
1104
+ //if we're limiting users by search
1105
+ if($s || $l)
1106
+ {
1107
+ $user_ids_query = "AND user_id IN(SELECT u.ID FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id WHERE mu.status = 'active' ";
1108
+ if($s)
1109
+ $user_ids_query .= "AND (u.user_login LIKE '%" . esc_sql($s) . "%' OR u.user_email LIKE '%" . esc_sql($s) . "%' OR um.meta_value LIKE '%" . esc_sql($s) . "%') ";
1110
+ if($l)
1111
+ $user_ids_query .= "AND mu.membership_id = '" . esc_sql($l) . "' ";
1112
+ $user_ids_query .= ")";
1113
+ }
1114
+ else
1115
+ $user_ids_query = "";
1116
+
1117
+ //4 queries to get annual earnings for each cycle period. currently ignoring trial periods and billing limits.
1118
+ $sqlQuery = "
1119
+ SELECT SUM((12/cycle_number)*billing_amount) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND cycle_period = 'Month' AND cycle_number <> 12 $user_ids_query
1120
+ UNION
1121
+ SELECT SUM((365/cycle_number)*billing_amount) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND cycle_period = 'Day' AND cycle_number <> 365 $user_ids_query
1122
+ UNION
1123
+ SELECT SUM((52/cycle_number)*billing_amount) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND cycle_period = 'Week' AND cycle_number <> 52 $user_ids_query
1124
+ UNION
1125
+ SELECT SUM(billing_amount) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND cycle_period = 'Year' $user_ids_query
1126
+ ";
1127
+
1128
+ $annual_revenues = $wpdb->get_col($sqlQuery);
1129
+
1130
+ $total = 0;
1131
+ foreach($annual_revenues as $r)
1132
+ {
1133
+ $total += $r;
1134
+ }
1135
+
1136
+ return $total;
1137
+ }
1138
+
1139
+ function pmpro_generateUsername($firstname = "", $lastname = "", $email = "")
1140
+ {
1141
+ global $wpdb;
1142
+
1143
+ //try first initial + last name, firstname, lastname
1144
+ $firstname = preg_replace("/[^A-Za-z]/", "", $firstname);
1145
+ $lastname = preg_replace("/[^A-Za-z]/", "", $lastname);
1146
+ if($firstname && $lastname)
1147
+ {
1148
+ $username = substr($firstname, 0, 1) . $lastname;
1149
+ }
1150
+ elseif($firstname)
1151
+ {
1152
+ $username = $firstname;
1153
+ }
1154
+ elseif($lastname)
1155
+ {
1156
+ $username = $lastname;
1157
+ }
1158
+
1159
+ //is it taken?
1160
+ $taken = $wpdb->get_var("SELECT user_login FROM $wpdb->users WHERE user_login = '" . esc_sql($username) . "' LIMIT 1");
1161
+
1162
+ if(!$taken)
1163
+ return $username;
1164
+
1165
+ //try the beginning of the email address
1166
+ $emailparts = explode("@", $email);
1167
+ if(is_array($emailparts))
1168
+ $email = preg_replace("/[^A-Za-z]/", "", $emailparts[0]);
1169
+
1170
+ if(!empty($email))
1171
+ {
1172
+ $username = $email;
1173
+ }
1174
+
1175
+ //is this taken? if not, add numbers until it works
1176
+ $taken = true;
1177
+ $count = 0;
1178
+ while($taken)
1179
+ {
1180
+ //add a # to the end
1181
+ if($count)
1182
+ {
1183
+ $username = preg_replace("/[0-9]/", "", $username) . $count;
1184
+ }
1185
+
1186
+ //taken?
1187
+ $taken = $wpdb->get_var("SELECT user_login FROM $wpdb->users WHERE user_login = '" . esc_sql($username) . "' LIMIT 1");
1188
+
1189
+ //increment the number
1190
+ $count++;
1191
+ }
1192
+
1193
+ //must have a good username now
1194
+ return $username;
1195
+ }
1196
+
1197
+ //get a new random code for discount codes
1198
+ function pmpro_getDiscountCode($seed = NULL)
1199
+ {
1200
+ global $wpdb;
1201
+
1202
+ while(empty($code))
1203
+ {
1204
+ $scramble = md5(AUTH_KEY . current_time('timestamp') . $seed . SECURE_AUTH_KEY);
1205
+ $code = substr($scramble, 0, 10);
1206
+ $check = $wpdb->get_var("SELECT code FROM $wpdb->pmpro_discount_codes WHERE code = '" . esc_sql($code) . "' LIMIT 1");
1207
+ if($check || is_numeric($code))
1208
+ $code = NULL;
1209
+ }
1210
+
1211
+ return strtoupper($code);
1212
+ }
1213
+
1214
+ //is a discount code valid
1215
+ function pmpro_checkDiscountCode($code, $level_id = NULL, $return_errors = false)
1216
+ {
1217
+ global $wpdb;
1218
+
1219
+ $error = false;
1220
+
1221
+ //make sure level id is int for security
1222
+ $level_id = intval($level_id);
1223
+
1224
+ //no code, no code
1225
+ if(empty($code))
1226
+ $error = __("No code was given to check.", "pmpro");
1227
+
1228
+ //get code from db
1229
+ if(!$error)
1230
+ {
1231
+ $dbcode = $wpdb->get_row("SELECT *, UNIX_TIMESTAMP(starts) as starts, UNIX_TIMESTAMP(expires) as expires FROM $wpdb->pmpro_discount_codes WHERE code ='" . esc_sql($code) . "' LIMIT 1");
1232
+
1233
+ //did we find it?
1234
+ if(empty($dbcode->id))
1235
+ $error = __("The discount code could not be found.", "pmpro");
1236
+ }
1237
+
1238
+ //check if the code has started
1239
+ if(!$error)
1240
+ {
1241
+ //fix the date timestamps
1242
+ $dbcode->starts = strtotime(date("m/d/Y", $dbcode->starts));
1243
+ $dbcode->expires = strtotime(date("m/d/Y", $dbcode->expires));
1244
+
1245
+ //today
1246
+ $today = strtotime(date("m/d/Y 00:00:00", current_time("timestamp")));
1247
+
1248
+ //has this code started yet?
1249
+ if(!empty($dbcode->starts) && $dbcode->starts > $today)
1250
+ $error = sprintf(__("This discount code goes into effect on %s.", "pmpro"), date(get_option('date_format'), $dbcode->starts));
1251
+ }
1252
+
1253
+ //check if the code is expired
1254
+ if(!$error)
1255
+ {
1256
+ if(!empty($dbcode->expires) && $dbcode->expires < $today)
1257
+ $error = sprintf(__("This discount code expired on %s.", "pmpro"), date(get_option('date_format'), $dbcode->expires));
1258
+ }
1259
+
1260
+ //have we run out of uses?
1261
+ if(!$error)
1262
+ {
1263
+ if($dbcode->uses > 0)
1264
+ {
1265
+ $used = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->pmpro_discount_codes_uses WHERE code_id = '" . $dbcode->id . "'");
1266
+ if($used >= $dbcode->uses)
1267
+ $error = __("This discount code is no longer valid.", "pmpro");
1268
+ }
1269
+ }
1270
+
1271
+ //if a level was passed check if this code applies
1272
+ if(!$error)
1273
+ {
1274
+ $pmpro_check_discount_code_levels = apply_filters("pmpro_check_discount_code_levels", true, $dbcode->id);
1275
+ if(!empty($level_id) && $pmpro_check_discount_code_levels)
1276
+ {
1277
+ $code_level = $wpdb->get_row("SELECT l.id, cl.*, l.name, l.description, l.allow_signups FROM $wpdb->pmpro_discount_codes_levels cl LEFT JOIN $wpdb->pmpro_membership_levels l ON cl.level_id = l.id WHERE cl.code_id = '" . $dbcode->id . "' AND cl.level_id = '" . $level_id . "' LIMIT 1");
1278
+
1279
+ if(empty($code_level))
1280
+ $error = __("This discount code does not apply to this membership level.", "pmpro");
1281
+ }
1282
+ }
1283
+
1284
+ //allow filter
1285
+ $pmpro_check_discount_code = apply_filters("pmpro_check_discount_code", !$error, $dbcode, $level_id, $code);
1286
+ if(is_string($pmpro_check_discount_code))
1287
+ $error = $pmpro_check_discount_code; //string returned, this is an error
1288
+ elseif(!$pmpro_check_discount_code && !$error)
1289
+ $error = true; //no error before, but filter returned error
1290
+ elseif($pmpro_check_discount_code)
1291
+ $error = false; //filter is true, so error false
1292
+
1293
+ //return
1294
+ if($error)
1295
+ {
1296
+ //there was an error
1297
+ if(!empty($return_errors))
1298
+ return array(false, $error);
1299
+ else
1300
+ return false;
1301
+ }
1302
+ else
1303
+ {
1304
+ //guess we're all good
1305
+ if(!empty($return_errors))
1306
+ return array(true, __("This discount code is okay.", "pmpro"));
1307
+ else
1308
+ return true;
1309
+ }
1310
+ }
1311
+
1312
+ function pmpro_no_quotes($s, $quotes = array("'", '"'))
1313
+ {
1314
+ return str_replace($quotes, "", $s);
1315
+ }
1316
+
1317
+ //from: http://www.php.net/manual/en/function.implode.php#86845
1318
+ function pmpro_implodeToEnglish($array)
1319
+ {
1320
+ // sanity check
1321
+ if (!$array || !count ($array))
1322
+ return '';
1323
+
1324
+ // get last element
1325
+ $last = array_pop ($array);
1326
+
1327
+ // if it was the only element - return it
1328
+ if (!count ($array))
1329
+ return $last;
1330
+
1331
+ return implode (', ', $array).' ' . __('and', 'pmpro') . ' '.$last;
1332
+ }
1333
+
1334
+ //from yoast wordpress seo
1335
+ function pmpro_text_limit( $text, $limit, $finish = '&hellip;')
1336
+ {
1337
+ if( strlen( $text ) > $limit ) {
1338
+ $text = substr( $text, 0, $limit );
1339
+ $text = substr( $text, 0, - ( strlen( strrchr( $text,' ') ) ) );
1340
+ $text .= $finish;
1341
+ }
1342
+ return $text;
1343
+ }
1344
+
1345
+ /* pmpro_getMembershipLevelForUser() returns the first active membership level for a user
1346
+ *
1347
+ * If $user_id is omitted, the value will be retrieved from $current_user.
1348
+ *
1349
+ * Return values:
1350
+ * Success returns the level object.
1351
+ * Failure returns false.
1352
+ */
1353
+ function pmpro_getMembershipLevelForUser($user_id = NULL, $force = false)
1354
+ {
1355
+ if(empty($user_id))
1356
+ {
1357
+ global $current_user;
1358
+ $user_id = $current_user->ID;
1359
+ }
1360
+
1361
+ if(empty($user_id))
1362
+ {
1363
+ return false;
1364
+ }
1365
+
1366
+ //make sure user id is int for security
1367
+ $user_id = intval($user_id);
1368
+
1369
+ global $all_membership_levels;
1370
+
1371
+ if(isset($all_membership_levels[$user_id]) && !$force)
1372
+ {
1373
+ return $all_membership_levels[$user_id];
1374
+ }
1375
+ else
1376
+ {
1377
+ global $wpdb;
1378
+ $all_membership_levels[$user_id] = $wpdb->get_row("SELECT
1379
+ l.id AS ID,
1380
+ l.id as id,
1381
+ mu.id as subscription_id,
1382
+ l.name AS name,
1383
+ l.description,
1384
+ l.expiration_number,
1385
+ l.expiration_period,
1386
+ mu.initial_payment,
1387
+ mu.billing_amount,
1388
+ mu.cycle_number,
1389
+ mu.cycle_period,
1390
+ mu.billing_limit,
1391
+ mu.trial_amount,
1392
+ mu.trial_limit,
1393
+ mu.code_id as code_id,
1394
+ UNIX_TIMESTAMP(startdate) as startdate,
1395
+ UNIX_TIMESTAMP(enddate) as enddate
1396
+ FROM {$wpdb->pmpro_membership_levels} AS l
1397
+ JOIN {$wpdb->pmpro_memberships_users} AS mu ON (l.id = mu.membership_id)
1398
+ WHERE mu.user_id = $user_id AND mu.status = 'active'
1399
+ LIMIT 1");
1400
+
1401
+ /**
1402
+ * pmpro_get_membership_level_for_user filter.
1403
+ *
1404
+ * Filters the returned level.
1405
+ *
1406
+ * @since 1.8.5.4
1407
+ *
1408
+ * @param object $level Level object.
1409
+ */
1410
+ $all_membership_levels[$user_id] = apply_filters('pmpro_get_membership_level_for_user', $all_membership_levels[$user_id]);
1411
+
1412
+ return $all_membership_levels[$user_id];
1413
+ }
1414
+ }
1415
+
1416
+ /* pmpro_getMembershipLevelsForUser() returns the membership levels for a user
1417
+ *
1418
+ * If $user_id is omitted, the value will be retrieved from $current_user.
1419
+ * By default it only includes actvie memberships.
1420
+ *
1421
+ * Return values:
1422
+ * Success returns an array of level objects.
1423
+ * Failure returns false.
1424
+ */
1425
+ function pmpro_getMembershipLevelsForUser($user_id = NULL, $include_inactive = false)
1426
+ {
1427
+ if(empty($user_id))
1428
+ {
1429
+ global $current_user;
1430
+ $user_id = $current_user->ID;
1431
+ }
1432
+
1433
+ if(empty($user_id))
1434
+ {
1435
+ return false;
1436
+ }
1437
+
1438
+ //make sure user id is int for security
1439
+ $user_id = intval($user_id);
1440
+
1441
+ global $wpdb;
1442
+
1443
+ $levels = $wpdb->get_results("SELECT
1444
+ l.id AS ID,
1445
+ l.id as id,
1446
+ mu.id as subscription_id,
1447
+ l.name,
1448
+ l.description,
1449
+ l.expiration_number,
1450
+ l.expiration_period,
1451
+ mu.initial_payment,
1452
+ mu.billing_amount,
1453
+ mu.cycle_number,
1454
+ mu.cycle_period,
1455
+ mu.billing_limit,
1456
+ mu.trial_amount,
1457
+ mu.trial_limit,
1458
+ mu.code_id as code_id,
1459
+ UNIX_TIMESTAMP(startdate) as startdate,
1460
+ UNIX_TIMESTAMP(enddate) as enddate
1461
+ FROM {$wpdb->pmpro_membership_levels} AS l
1462
+ JOIN {$wpdb->pmpro_memberships_users} AS mu ON (l.id = mu.membership_id)
1463
+ WHERE mu.user_id = $user_id".($include_inactive?"":" AND mu.status = 'active'"));
1464
+ /**
1465
+ * pmpro_get_membership_levels_for_user filter.
1466
+ *
1467
+ * Filters the returned levels.
1468
+ *
1469
+ * @since 1.8.5.4
1470
+ *
1471
+ * @param array $levels Array of level objects.
1472
+ */
1473
+ $levels = apply_filters('pmpro_get_membership_levels_for_user', $levels);
1474
+
1475
+ return $levels;
1476
+ }
1477
+
1478
+ /* pmpro_getLevel() returns the level object for a level
1479
+ *
1480
+ * $level may be the level id or name
1481
+ *
1482
+ * Return values:
1483
+ * Success returns the level object.
1484
+ * Failure returns false.
1485
+ */
1486
+ function pmpro_getLevel($level)
1487
+ {
1488
+ global $pmpro_levels;
1489
+
1490
+ if(is_object($level) && !empty($level->id))
1491
+ $level = $level->id;
1492
+
1493
+ //was a name passed? (Todo: make sure level names have at least one non-numeric character.
1494
+ if(is_numeric($level))
1495
+ {
1496
+ $level_id = intval($level);
1497
+ if(isset($pmpro_levels[$level_id]))
1498
+ {
1499
+ return $pmpro_levels[$level_id];
1500
+ }
1501
+ else
1502
+ {
1503
+ global $wpdb;
1504
+ $pmpro_levels[$level_id] = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . $level_id . "' LIMIT 1");
1505
+ return $pmpro_levels[$level_id];
1506
+ }
1507
+ }
1508
+ else
1509
+ {
1510
+ global $wpdb;
1511
+ $level_obj = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE name = '" . esc_sql($level) . "' LIMIT 1");
1512
+
1513
+ if(!empty($level_obj))
1514
+ $level_id = $level_obj->id;
1515
+ else
1516
+ return false;
1517
+
1518
+ $pmpro_levels[$level_id] = $level_obj;
1519
+ return $pmpro_levels[$level_id];
1520
+ }
1521
+ }
1522
+
1523
+ /*
1524
+ Function to populate pmpro_levels with all levels. We query the DB every time just to be sure we have the latest.
1525
+ This should be called if you want to be sure you get all levels as $pmpro_levels may only have a subset of levels.
1526
+ */
1527
+ function pmpro_getAllLevels($include_hidden = false, $force = false)
1528
+ {
1529
+ global $pmpro_levels, $wpdb;
1530
+
1531
+ //just use what's cached (doesn't take into account include_hidden setting)
1532
+ if(!empty($pmpro_levels) && !$force)
1533
+ return $pmpro_levels;
1534
+
1535
+ //build query
1536
+ $sqlQuery = "SELECT * FROM $wpdb->pmpro_membership_levels ";
1537
+ if(!$include_hidden)
1538
+ $sqlQuery .= " WHERE allow_signups = 1 ORDER BY id";
1539
+
1540
+ //get levels from the DB
1541
+ $raw_levels = $wpdb->get_results($sqlQuery);
1542
+
1543
+ //lets put them into an array where the key is the id of the level
1544
+ $pmpro_levels = array();
1545
+ foreach($raw_levels as $raw_level)
1546
+ {
1547
+ $pmpro_levels[$raw_level->id] = $raw_level;
1548
+ }
1549
+
1550
+ return $pmpro_levels;
1551
+ }
1552
+
1553
+ function pmpro_getCheckoutButton($level_id, $button_text = NULL, $classes = NULL)
1554
+ {
1555
+ if(empty($button_text))
1556
+ $button_text = __("Sign Up for !!name!! Now", "pmpro");
1557
+
1558
+ if(empty($classes))
1559
+ $classes = "pmpro_btn";
1560
+
1561
+ if(empty($level_id))
1562
+ $r = __("Please specify a level id.", "pmpro");
1563
+ else
1564
+ {
1565
+ //get level
1566
+ $level = pmpro_getLevel($level_id);
1567
+
1568
+ //replace vars
1569
+ $replacements = array(
1570
+ "!!id!!" => $level->id,
1571
+ "!!name!!" => $level->name,
1572
+ "!!description!!" => $level->description,
1573
+ "!!confirmation!!" => $level->confirmation,
1574
+ "!!initial_payment!!" => $level->initial_payment,
1575
+ "!!billing_amount!!" => $level->billing_amount,
1576
+ "!!cycle_number!!" => $level->cycle_number,
1577
+ "!!cycle_period!!" => $level->cycle_period,
1578
+ "!!billing_limit!!" => $level->billing_limit,
1579
+ "!!trial_amount!!" => $level->trial_amount,
1580
+ "!!trial_limit!!" => $level->trial_limit,
1581
+ "!!expiration_number!!" => $level->expiration_number,
1582
+ "!!expiration_period!!" => $level->expiration_period
1583
+ );
1584
+ $button_text = str_replace(array_keys($replacements), $replacements, $button_text);
1585
+
1586
+ //button text
1587
+ $r = "<a href=\"" . pmpro_url("checkout", "?level=" . $level_id) . "\" class=\"" . $classes . "\">" . $button_text . "</a>";
1588
+ }
1589
+ return $r;
1590
+ }
1591
+
1592
+ /**
1593
+ * Get the "domain" from a URL. By domain, we mean the host name, minus any subdomains. So just the domain and TLD.
1594
+ *
1595
+ * @param string $url The URL to parse. (generally pass site_url() in WP)
1596
+ * @return string The domain.
1597
+ */
1598
+ function pmpro_getDomainFromURL($url = NULL)
1599
+ {
1600
+ $domainparts = parse_url($url);
1601
+ $domainparts = explode(".", $domainparts['host']);
1602
+ if(count($domainparts) > 1)
1603
+ {
1604
+ //check for ips
1605
+ $isip = true;
1606
+ foreach($domainparts as $part)
1607
+ {
1608
+ if(!is_numeric($part))
1609
+ {
1610
+ $isip = false;
1611
+ break;
1612
+ }
1613
+ }
1614
+
1615
+ if($isip)
1616
+ {
1617
+ //ip, e.g. 127.1.1.1
1618
+ $domain = implode(".", $domainparts);
1619
+ }
1620
+ else
1621
+ {
1622
+ //www.something.com, etc.
1623
+ $domain = $domainparts[count($domainparts)-2] . "." . $domainparts[count($domainparts)-1];
1624
+ }
1625
+ }
1626
+ else
1627
+ {
1628
+ //localhost or another single word domain
1629
+ $domain = $domainparts[0];
1630
+ }
1631
+
1632
+ return $domain;
1633
+ }
1634
+
1635
+ /*
1636
+ Get a member's start date... either in general or for a specific level_id.
1637
+ */
1638
+ if(!function_exists("pmpro_getMemberStartdate"))
1639
+ {
1640
+ function pmpro_getMemberStartdate($user_id = NULL, $level_id = 0)
1641
+ {
1642
+ if(empty($user_id))
1643
+ {
1644
+ global $current_user;
1645
+ $user_id = $current_user->ID;
1646
+ }
1647
+
1648
+ //make sure user and level id are int for security
1649
+ $user_id = intval($user_id);
1650
+ $level_id = intval($level_id);
1651
+
1652
+ global $pmpro_startdates; //for cache
1653
+ if(empty($pmpro_startdates[$user_id][$level_id]))
1654
+ {
1655
+ global $wpdb;
1656
+
1657
+ if(!empty($level_id))
1658
+ $sqlQuery = "SELECT UNIX_TIMESTAMP(startdate) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND membership_id IN(" . esc_sql($level_id) . ") AND user_id = '" . $user_id . "' ORDER BY id LIMIT 1";
1659
+ else
1660
+ $sqlQuery = "SELECT UNIX_TIMESTAMP(startdate) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND user_id = '" . $user_id . "' ORDER BY id LIMIT 1";
1661
+
1662
+ $startdate = apply_filters("pmpro_member_startdate", $wpdb->get_var($sqlQuery), $user_id, $level_id);
1663
+
1664
+ $pmpro_startdates[$user_id][$level_id] = $startdate;
1665
+ }
1666
+
1667
+ return $pmpro_startdates[$user_id][$level_id];
1668
+ }
1669
+ }
1670
+
1671
+ /*
1672
+ How long has this member been a member
1673
+ */
1674
+ if(!function_exists("pmpro_getMemberDays"))
1675
+ {
1676
+ function pmpro_getMemberDays($user_id = NULL, $level_id = 0)
1677
+ {
1678
+ if(empty($user_id))
1679
+ {
1680
+ global $current_user;
1681
+ $user_id = $current_user->ID;
1682
+ }
1683
+
1684
+ global $pmpro_member_days;
1685
+ if(empty($pmpro_member_days[$user_id][$level_id]))
1686
+ {
1687
+ $startdate = pmpro_getMemberStartdate($user_id, $level_id);
1688
+
1689
+ //check that there was a startdate at all
1690
+ if(empty($startdate))
1691
+ $pmpro_member_days[$user_id][$level_id] = 0;
1692
+ else
1693
+ {
1694
+ $now = current_time('timestamp');
1695
+ $days = ($now - $startdate)/3600/24;
1696
+
1697
+ $pmpro_member_days[$user_id][$level_id] = $days;
1698
+ }
1699
+ }
1700
+
1701
+ return $pmpro_member_days[$user_id][$level_id];
1702
+ }
1703
+ }
1704
+
1705
+ //the start of a message handling script
1706
+ function pmpro_setMessage($message, $type, $force = false)
1707
+ {
1708
+ global $pmpro_msg, $pmpro_msgt;
1709
+
1710
+ //for now, we only show the first message generated
1711
+ if($force || empty($pmpro_msg))
1712
+ {
1713
+ $pmpro_msg = $message;
1714
+ $pmpro_msgt = $type;
1715
+ }
1716
+ }
1717
+
1718
+ /**
1719
+ * Show a a PMPro message set via pmpro_setMessage
1720
+ *
1721
+ * @since 1.8.5
1722
+ */
1723
+ function pmpro_showMessage()
1724
+ {
1725
+ global $pmpro_msg, $pmpro_msgt;
1726
+
1727
+ if(!empty($pmpro_msg))
1728
+ {
1729
+ ?>
1730
+ <div class="<?php echo $pmpro_msgt;?>">
1731
+ <p><?php echo $pmpro_msg;?></p>
1732
+ </div>
1733
+ <?php
1734
+ }
1735
+ }
1736
+
1737
+ //used in class definitions for input fields to see if there was an error
1738
+ function pmpro_getClassForField($field)
1739
+ {
1740
+ global $pmpro_error_fields, $pmpro_required_billing_fields, $pmpro_required_user_fields;
1741
+ $classes = array();
1742
+
1743
+ //error on this field?
1744
+ if(!empty($pmpro_error_fields) && in_array($field, $pmpro_error_fields))
1745
+ {
1746
+ $classes[] = "pmpro_error";
1747
+ }
1748
+
1749
+ if(is_array($pmpro_required_billing_fields) && is_array($pmpro_required_user_fields))
1750
+ $required_fields = array_merge(array_keys($pmpro_required_billing_fields), array_keys($pmpro_required_user_fields));
1751
+ elseif(is_array($pmpro_required_billing_fields))
1752
+ $required_fields = array_keys($pmpro_required_billing_fields);
1753
+ elseif(is_array($pmpro_required_user_fields))
1754
+ $required_fields = array_keys($pmpro_required_user_fields);
1755
+ else
1756
+ $required_fields = array();
1757
+
1758
+ //required?
1759
+ if(in_array($field, $required_fields))
1760
+ {
1761
+ $classes[] = "pmpro_required";
1762
+ }
1763
+
1764
+ $classes = apply_filters("pmpro_field_classes", $classes, $field);
1765
+
1766
+ if(!empty($classes))
1767
+ return implode(" ", $classes);
1768
+ else
1769
+ return "";
1770
+ }
1771
+
1772
+ //get a var from $_GET or $_POST
1773
+ function pmpro_getParam($index, $method = "REQUEST", $default = "")
1774
+ {
1775
+ if($method == "REQUEST")
1776
+ {
1777
+ if(!empty($_REQUEST[$index]))
1778
+ return $_REQUEST[$index];
1779
+ }
1780
+ elseif($method == "POST")
1781
+ {
1782
+ if(!empty($_POST[$index]))
1783
+ return $_POST[$index];
1784
+ }
1785
+ elseif($method == "GET")
1786
+ {
1787
+ if(!empty($_GET[$index]))
1788
+ return $_GET[$index];
1789
+ }
1790
+
1791
+ return $default;
1792
+ }
1793
+
1794
+ /*
1795
+ Format an address from address, city, state, zip, country, and phone
1796
+ */
1797
+ function pmpro_formatAddress($name, $address1, $address2, $city, $state, $zip, $country, $phone, $nl2br = true)
1798
+ {
1799
+ $address = "";
1800
+
1801
+ if(!empty($name))
1802
+ $address .= $name . "\n";
1803
+
1804
+ if(!empty($address1))
1805
+ $address .= $address1 . "\n";
1806
+
1807
+ if(!empty($address2))
1808
+ $address .= $address2 . "\n";
1809
+
1810
+ if(!empty($city) && !empty($state))
1811
+ {
1812
+ $address .= $city . ", " . $state;
1813
+
1814
+ if(!empty($zip))
1815
+ $address .= " " . $zip;
1816
+
1817
+ $address .= "\n";
1818
+ }
1819
+
1820
+ if(!empty($country))
1821
+ $address .= $country . "\n";
1822
+
1823
+ if(!empty($phone))
1824
+ $address .= formatPhone($phone);
1825
+
1826
+ if($nl2br)
1827
+ $address = nl2br($address);
1828
+
1829
+ return $address;
1830
+ }
1831
+
1832
+ /*
1833
+ Checks if all required settings are set.
1834
+ */
1835
+ function pmpro_is_ready()
1836
+ {
1837
+ global $wpdb, $pmpro_pages, $pmpro_level_ready, $pmpro_gateway_ready, $pmpro_pages_ready;
1838
+
1839
+ //check if there is at least one level
1840
+ $pmpro_level_ready = (bool)$wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_levels LIMIT 1");
1841
+
1842
+ //check if the gateway settings are good. first check if it's needed (is there paid membership level)
1843
+ $paid_membership_level = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_levels WHERE allow_signups = 1 AND (initial_payment > 0 OR billing_amount > 0 OR trial_amount > 0) LIMIT 1");
1844
+ $paid_user_subscription = $wpdb->get_var("SELECT user_id FROM $wpdb->pmpro_memberships_users WHERE initial_payment > 0 OR billing_amount > 0 OR trial_amount > 0 LIMIT 1");
1845
+
1846
+ if(empty($paid_membership_level) && empty($paid_user_subscription))
1847
+ {
1848
+ //no paid membership level now or attached to a user. we don't need the gateway setup
1849
+ $pmpro_gateway_ready = true;
1850
+ }
1851
+ else
1852
+ {
1853
+ $gateway = pmpro_getOption("gateway");
1854
+ if($gateway == "authorizenet")
1855
+ {
1856
+ if(pmpro_getOption("gateway_environment") && pmpro_getOption("loginname") && pmpro_getOption("transactionkey"))
1857
+ $pmpro_gateway_ready = true;
1858
+ else
1859
+ $pmpro_gateway_ready = false;
1860
+ }
1861
+ elseif($gateway == "paypal" || $gateway == "paypalexpress")
1862
+ {
1863
+ if(pmpro_getOption("gateway_environment") && pmpro_getOption("gateway_email") && pmpro_getOption("apiusername") && pmpro_getOption("apipassword") && pmpro_getOption("apisignature"))
1864
+ $pmpro_gateway_ready = true;
1865
+ else
1866
+ $pmpro_gateway_ready = false;
1867
+ }
1868
+ elseif($gateway == "paypalstandard")
1869
+ {
1870
+ if(pmpro_getOption("gateway_environment") && pmpro_getOption("gateway_email"))
1871
+ $pmpro_gateway_ready = true;
1872
+ else
1873
+ $pmpro_gateway_ready = false;
1874
+ }
1875
+ elseif($gateway == "payflowpro")
1876
+ {
1877
+ if(pmpro_getOption("payflow_partner") && pmpro_getOption("payflow_vendor") && pmpro_getOption("payflow_user") && pmpro_getOption("payflow_pwd"))
1878
+ $pmpro_gateway_ready = true;
1879
+ else
1880
+ $pmpro_gateway_ready = false;
1881
+ }
1882
+ elseif($gateway == "stripe")
1883
+ {
1884
+ if(pmpro_getOption("gateway_environment") && pmpro_getOption("stripe_secretkey") && pmpro_getOption("stripe_publishablekey"))
1885
+ $pmpro_gateway_ready = true;
1886
+ else
1887
+ $pmpro_gateway_ready = false;
1888
+ }
1889
+ elseif($gateway == "braintree")
1890
+ {
1891
+ if(pmpro_getOption("gateway_environment") && pmpro_getOption("braintree_merchantid") && pmpro_getOption("braintree_publickey") && pmpro_getOption("braintree_privatekey"))
1892
+ $pmpro_gateway_ready = true;
1893
+ else
1894
+ $pmpro_gateway_ready = false;
1895
+ }
1896
+ elseif($gateway == "twocheckout")
1897
+ {
1898
+ if(pmpro_getOption("gateway_environment") && pmpro_getOption("twocheckout_apiusername") && pmpro_getOption("twocheckout_apipassword"))
1899
+ $pmpro_gateway_ready = true;
1900
+ else
1901
+ $pmpro_gateway_ready = false;
1902
+ }
1903
+ elseif($gateway == "cybersource")
1904
+ {
1905
+ if(pmpro_getOption("gateway_environment") && pmpro_getOption("cybersource_merchantid") && pmpro_getOption("cybersource_securitykey"))
1906
+ $pmpro_gateway_ready = true;
1907
+ else
1908
+ $pmpro_gateway_ready = false;
1909
+ }
1910
+ elseif($gateway == "check")
1911
+ {
1912
+ $pmpro_gateway_ready = true;
1913
+ }
1914
+ else
1915
+ {
1916
+ $pmpro_gateway_ready = false;
1917
+ }
1918
+ }
1919
+
1920
+ //check if we have all pages
1921
+ if($pmpro_pages["account"] &&
1922
+ $pmpro_pages["billing"] &&
1923
+ $pmpro_pages["cancel"] &&
1924
+ $pmpro_pages["checkout"] &&
1925
+ $pmpro_pages["confirmation"] &&
1926
+ $pmpro_pages["invoice"] &&
1927
+ $pmpro_pages["levels"])
1928
+ $pmpro_pages_ready = true;
1929
+ else
1930
+ $pmpro_pages_ready = false;
1931
+
1932
+ //now check both
1933
+ if($pmpro_gateway_ready && $pmpro_pages_ready)
1934
+ $r = true;
1935
+ else
1936
+ $r = false;
1937
+
1938
+ /**
1939
+ * Filter to determine if PMPro setup is complete or
1940
+ * if notices or warnings need to be shown in the PMPro settings.
1941
+ *
1942
+ * Note: The filter should return true or false and also set
1943
+ * the $pmpro_level_ready, $pmpro_gateway_ready, $pmpro_pages_ready global variabls.
1944
+ *
1945
+ * @since 1.8.4.5
1946
+ *
1947
+ * @param bool $r ready?
1948
+ */
1949
+ $r = apply_filters('pmpro_is_ready', $r);
1950
+
1951
+ return $r;
1952
+ }
1953
+
1954
+ /**
1955
+ * Format a price per the currency settings.
1956
+ *
1957
+ * @since 1.7.15
1958
+ */
1959
+ function pmpro_formatPrice($price)
1960
+ {
1961
+ global $pmpro_currency, $pmpro_currency_symbol, $pmpro_currencies;
1962
+
1963
+ //start with the price formatted with two decimals
1964
+ $formatted = number_format($price, 2);
1965
+
1966
+ //settings stored in array?
1967
+ if(!empty($pmpro_currencies[$pmpro_currency]) && is_array($pmpro_currencies[$pmpro_currency]))
1968
+ {
1969
+ //format number do decimals, with decimal_separator and thousands_separator
1970
+ $formatted = number_format($price,
1971
+ (isset($pmpro_currencies[$pmpro_currency]['decimals']) ? (int)$pmpro_currencies[$pmpro_currency]['decimals'] : 2),
1972
+ (isset($pmpro_currencies[$pmpro_currency]['decimal_separator']) ? $pmpro_currencies[$pmpro_currency]['decimal_separator'] : '.'),
1973
+ (isset($pmpro_currencies[$pmpro_currency]['thousands_separator']) ? $pmpro_currencies[$pmpro_currency]['thousands_separator'] : ',')
1974
+ );
1975
+
1976
+ //which side is the symbol on?
1977
+ if(!empty($pmpro_currencies[$pmpro_currency]['position']) && $pmpro_currencies[$pmpro_currency]['position']== 'left')
1978
+ $formatted = $pmpro_currency_symbol . $formatted;
1979
+ else
1980
+ $formatted = $formatted . $pmpro_currency_symbol;
1981
+ }
1982
+ else
1983
+ $formatted = $pmpro_currency_symbol . $formatted; //default to symbol on the left
1984
+
1985
+ //filter
1986
+ return apply_filters('pmpro_format_price', $formatted, $price, $pmpro_currency, $pmpro_currency_symbol);
1987
+ }
1988
+
1989
+ /**
1990
+ * Which side does the currency symbol go on?
1991
+ *
1992
+ * @since 1.7.15
1993
+ */
1994
+ function pmpro_getCurrencyPosition()
1995
+ {
1996
+ global $pmpro_currency, $pmpro_currencies;
1997
+
1998
+ if(!empty($pmpro_currencies[$pmpro_currency]) && is_array($pmpro_currencies[$pmpro_currency]) && !empty($pmpro_currencies[$pmpro_currency]['position']))
1999
+ return $pmpro_currencies[$pmpro_currency]['position'];
2000
+ else
2001
+ return "left";
2002
+ }
2003
+
2004
+ /*
2005
+ * What gateway should we be using?
2006
+ *
2007
+ * @since 1.8
2008
+ */
2009
+ function pmpro_getGateway()
2010
+ {
2011
+ //grab from param or options
2012
+ if (!empty($_REQUEST['gateway']))
2013
+ $gateway = $_REQUEST['gateway']; //gateway passed as param
2014
+ elseif (!empty($_REQUEST['review']))
2015
+ $gateway = "paypalexpress"; //if review param assume paypalexpress
2016
+ else
2017
+ $gateway = pmpro_getOption("gateway"); //get from options
2018
+
2019
+ //set valid gateways - the active gateway in the settings and any gateway added through the filter will be allowed
2020
+ if(pmpro_getOption("gateway", true) == "paypal")
2021
+ $valid_gateways = apply_filters("pmpro_valid_gateways", array("paypal", "paypalexpress"));
2022
+ else
2023
+ $valid_gateways = apply_filters("pmpro_valid_gateways", array(pmpro_getOption("gateway", true)));
2024
+
2025
+ //make sure it's valid
2026
+ if(!in_array($gateway, $valid_gateways))
2027
+ $gateway = false;
2028
+
2029
+ //filter for good measure
2030
+ $gateway = apply_filters('pmpro_get_gateway', $gateway, $valid_gateways);
2031
+
2032
+ return $gateway;
2033
+ }
2034
+
2035
+ /*
2036
+ * Does the date provided fall in this month.
2037
+ * Used in logins/visits/views report.
2038
+ *
2039
+ * @since 1.8.3
2040
+ */
2041
+ function pmpro_isDateThisMonth($str)
2042
+ {
2043
+ $now = current_time('timestamp');
2044
+ $this_month = intval(date("n", $now));
2045
+ $this_year = intval(date("Y", $now));
2046
+
2047
+ $date = strtotime($str, $now);
2048
+ $date_month = intval(date("n", $date));
2049
+ $date_year = intval(date("Y", $date));
2050
+
2051
+ if($date_month === $this_month && $date_year === $this_year)
2052
+ return true;
2053
+ else
2054
+ return false;
2055
+ }
2056
+
2057
+ /**
2058
+ * Function to generate PMPro front end pages.
2059
+ *
2060
+ * @param array $pages {
2061
+ * Formatted as array($name => $title) or array(array('title'=>'The Title', 'content'=>'The Content'))
2062
+ *
2063
+ * @type string $name Page name. (Letters, numbers, and underscores only.)
2064
+ * @type string $title Page title.
2065
+ * }
2066
+ * @return array $created_pages Created page IDs.
2067
+ * @since 1.8.5
2068
+ */
2069
+ function pmpro_generatePages($pages) {
2070
+
2071
+ global $pmpro_pages;
2072
+
2073
+ $pages_created = array();
2074
+
2075
+ if(!empty($pages)) {
2076
+ foreach($pages as $name => $page) {
2077
+
2078
+ //does it already exist?
2079
+ if(!empty($pmpro_pages[$name]))
2080
+ continue;
2081
+
2082
+ //no id set. create an array to store the page info
2083
+ if(is_array($page)) {
2084
+ $title = $page['title'];
2085
+ $content = $page['content'];
2086
+ } else {
2087
+ $title = $page;
2088
+ $content = '[pmpro_' . $name . ']';
2089
+ }
2090
+
2091
+ $insert = array(
2092
+ 'post_title' => $title,
2093
+ 'post_status' => 'publish',
2094
+ 'post_type' => 'page',
2095
+ 'post_content' => $content,
2096
+ 'comment_status' => 'closed',
2097
+ 'ping_status' => 'closed'
2098
+ );
2099
+
2100
+ //make non-account pages a subpage of account
2101
+ if ($name != "account") {
2102
+ $insert['post_parent'] = $pmpro_pages['account'];
2103
+ }
2104
+
2105
+ //create the page
2106
+ $pmpro_pages[$name] = wp_insert_post($insert);
2107
+
2108
+ //update the option too
2109
+ pmpro_setOption($name . "_page_id", $pmpro_pages[$name]);
2110
+ $pages_created[] = $pmpro_pages[$name];
2111
+ }
2112
+ }
2113
+
2114
+ return $pages_created;
2115
+ }
2116
+
includes/profile.php CHANGED
@@ -344,4 +344,5 @@ function pmpro_membership_level_profile_fields_update()
344
  }
345
  add_action( 'show_user_profile', 'pmpro_membership_level_profile_fields' );
346
  add_action( 'edit_user_profile', 'pmpro_membership_level_profile_fields' );
347
- add_action( 'profile_update', 'pmpro_membership_level_profile_fields_update' );
 
344
  }
345
  add_action( 'show_user_profile', 'pmpro_membership_level_profile_fields' );
346
  add_action( 'edit_user_profile', 'pmpro_membership_level_profile_fields' );
347
+ add_action( 'personal_options_update', 'pmpro_membership_level_profile_fields_update' );
348
+ add_action( 'edit_user_profile_update', 'pmpro_membership_level_profile_fields_update' );
includes/services.php CHANGED
@@ -69,6 +69,30 @@ function pmpro_wp_ajax_orders_csv()
69
  }
70
  add_action('wp_ajax_orders_csv', 'pmpro_wp_ajax_orders_csv');
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  function pmpro_update_level_order() {
73
  echo pmpro_setOption('level_order');
74
  exit;
69
  }
70
  add_action('wp_ajax_orders_csv', 'pmpro_wp_ajax_orders_csv');
71
 
72
+ /**
73
+ * Load the Orders print view.
74
+ *
75
+ * @since 1.8.6
76
+ */
77
+ function pmpro_orders_print_view() {
78
+ require_once(dirname(__FILE__) . "/../adminpages/orders-print.php");
79
+ exit;
80
+ }
81
+ add_action('wp_ajax_pmpro_orders_print_view', 'pmpro_orders_print_view');
82
+
83
+ /**
84
+ * Get order JSON.
85
+ *
86
+ * @since 1.8.6
87
+ */
88
+ function pmpro_get_order_json() {
89
+ $order_id = $_REQUEST['order_id'];
90
+ $order = new MemberOrder($order_id);
91
+ echo json_encode($order);
92
+ exit;
93
+ }
94
+ add_action('wp_ajax_pmpro_get_order_json', 'pmpro_get_order_json');
95
+
96
  function pmpro_update_level_order() {
97
  echo pmpro_setOption('level_order');
98
  exit;
languages/email/vi_VN/admin_change.html ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <p>Admin của !!sitename!! đã thay đổi kiểu thành viên của bạn.</p>
2
+
3
+ <p>!!membership_change!!.</p>
4
+
5
+ <p>Nếu bạn không yêu cầu thay đổi kiểu thành viên và muốn biết thêm thông tin xin vui lòng liên hệ với chúng tôi tại !!siteemail!!</p>
6
+
7
+ <p>Đăng nhập vào tài khoản thành viên của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/admin_change_admin.html ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <p>Admin của !!sitename!! đã thay đổi kiểu thành viên cho !!name!!.</p>
2
+
3
+ <p>!!membership_change!!.</p>
4
+
5
+ <p>Đăng nhập với WordPress admin ở đây: !!login_link!!</p>
languages/email/vi_VN/billing.html ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Thông tin thanh toán của bạn tại !!sitename!! đã thay đổi.</p>
2
+
3
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
4
+ <p>
5
+ Thông tin thanh toán:<br />
6
+ !!billing_address!!
7
+ </p>
8
+
9
+ <p>
10
+ !!cardtype!!: !!accountnumber!!<br />
11
+ Hết hạn: !!expirationmonth!!/!!expirationyear!!
12
+ </p>
13
+
14
+ <p>Nếu bạn không yêu cầu thay đổi thông tin thanh toán xin vui lòng liên hệ với chúng tôi tại !!siteemail!!</p>
15
+
16
+ <p>Đăng nhập vào tài khoản thành viên của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/billing_admin.html ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p> cho !!display_name!! tại !!sitename!! đã thay đổi.</p>
2
+
3
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
4
+ <p>
5
+ Thông tin thanh toán:<br />
6
+ !!billing_name!!<br />
7
+ !!billing_street!!<br />
8
+ !!billing_city!!, !!billing_state!! !!billing_zip!! !!billing_country!!
9
+ !!billing_phone!!
10
+ </p>
11
+
12
+ <p>
13
+ !!cardtype!!: !!accountnumber!!<br />
14
+ Hết hạn: !!expirationmonth!!/!!expirationyear!!
15
+ </p>
16
+
17
+ <p>Đăng nhập vào bảng điều khiển WordPressZ ở đây: !!login_link!!</p>
languages/email/vi_VN/billing_failure.html ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Việc thanh toán tiền cho đăng ký học này tại !!sitename!! đã thất bại. <strong> Vui lòng click vào link dưới đây để đăng nhập và cập nhật thông tin thanh toán để tránh bị ngừng tài khoản. !!login_link!!</strong></p>
2
+
3
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
4
+ <p>Các thông tin tài khoản gần đây nhất mà chúng tôi có trong hồ sơ là:</p>
5
+
6
+ <p>!!billing_address!!</p>
7
+
8
+ <p>
9
+ !!cardtype!!: !!accountnumber!!<br />
10
+ Hết hạn: !!expirationmonth!!/!!expirationyear!!
11
+ </p>
languages/email/vi_VN/billing_failure_admin.html ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Thanh toán thất bại</p>
2
+
3
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
4
+ <p>Các thông tin tài khoản gần đây nhất mà chúng tôi có trong hồ sơ là is:</p>
5
+
6
+ <p>!!billing_address!!</p>
7
+
8
+ <p>
9
+ !!cardtype!!: !!accountnumber!!<br />
10
+ Hết hạn: !!expirationmonth!!/!!expirationyear!!
11
+ </p>
languages/email/vi_VN/cancel.html ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <p>Quyền thành viên của bạn !!sitename!! đã bị hủy bỏ.</p>
2
+
3
+ <p>Nếu bạn không yêu cầu hủy bỏ và muốn biết thêm thông tin xin vui lòng liên hệ với chúng tôi tại !!siteemail!!</p>
languages/email/vi_VN/cancel_admin.html ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <p>Quyên thành viên của !!user_login!! tại !!sitename!! đã bi hủy.</p>
2
+
3
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
4
+ <p>Kiểu thành viên: !!membership_level_name!!</p>
5
+ <p>Ngày bắt đầu: !!startdate!!</p>
6
+ <p>Ngày hủy bỏ: !!enddate!!</p>
7
+
8
+ <p>Đăng nhập để vào phần quản trị của WordPress của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/checkout_check.html ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Cám ơn bạn đã đăng ký thành viên tại !!sitename!!. Tài khoản thành viên của bạn được kích hoạt ngay bây giờ.</p>
2
+
3
+ !!instructions!!
4
+
5
+ <p>Dưới đây là chi tiết về tài khoản thành viên của bạn và biên nhận của hóa đơn cho việc tạo thành viên lần đầu của bạn.</p>
6
+
7
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
8
+ <p>Kiểu thành viên !!membership_level_name!!</p>
9
+ <p>Phí thành viên: !!membership_cost!!</p>
10
+ !!membership_expiration!! !!discount_code!!
11
+
12
+ <p>
13
+ Hóa đơn số!!invoice_id!! on !!invoice_date!!<br />
14
+ Hóa Đơn Tổng: !!invoice_total!!
15
+ </p>
16
+
17
+ <p>Đăng nhập để vào tài khoản của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/checkout_check_admin.html ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Có một thành viên mới thanh toán tại !!sitename!!.</p>
2
+
3
+ <p><strong>Họ đã chọn thanh toán bằng đánh dấu vào.</strong></p>
4
+
5
+ <p>Dưới đây là chi tiết về tài khoản của thành viên mới và biên nhận cho hóa đơn thành viên lần đầu.</p>
6
+
7
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
8
+ <p>Kiểu thành viên: !!membership_level_name!!</p>
9
+ <p>Phí thành viên: !!membership_cost!!</p>
10
+ !!membership_expiration!! !!discount_code!!
11
+
12
+ <p>
13
+ Số hóa đơn!!invoice_id!! on !!invoice_date!!<br />
14
+ Hóa đơn tổng: $!!invoice_total!!
15
+ </p>
16
+
17
+ <p>Đăng nhập để vào tài khoản của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/checkout_express.html ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Cảm ơn bạn đã đang ký thành viên tại !!sitename!!. Tài kh oản than9hf viên của bạn sẽ được kishs hoạt ngay.</p>
2
+ <p>Dưới đây là chi tiết về tài khoản thành viên của bạn và biên nhận cho hóa đơn cho thành viên lần đầu của bạn.</p>
3
+
4
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
5
+ <p>Kiểu thành viên: !!membership_level_name!!</p>
6
+ <p>Phí thành viên: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
+
9
+ <p>
10
+ Số hóa đơn!!invoice_id!! on !!invoice_date!!<br />
11
+ Hóa đơn tổng: !!invoice_total!!
12
+ </p>
13
+
14
+ <p>Đăng nhập để vào tài khoản của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/checkout_express_admin.html ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Có một thành viên mới thanh toán tại !!sitename!!.</p>
2
+ <p>Dưới đây là chi tiết về tài khoản thành viên của bạn và biên nhận cho hóa đơn cho thành viên lần đầu của bạn.</p>
3
+
4
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
5
+ <p>Kiểu thành viên: !!membership_level_name!!</p>
6
+ <p>Phí thành viên: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
+
9
+ <p>
10
+ Số hóa đơn!!invoice_id!! on !!invoice_date!!<br />
11
+ Hóa đơn tổng: !!invoice_total!!
12
+ </p>
13
+
14
+ <p>Đăng nhập để vào tài khoản của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/checkout_free.html ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <p>Cảm ơn bạn đã đang ký thành viên tại !!sitename!!. Tài khoản thành viên của bạn sẽ được kích hoạt ngay.</p>
2
+ <p>Below are details about your membership Tài khoản.</p>
3
+
4
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
5
+ <p>Kiểu thành viên: !!membership_level_name!!</p>
6
+ !!membership_expiration!! !!discount_code!!
7
+
8
+ <p>Đăng nhập để vào tài khoản của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/checkout_free_admin.html ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <p>Có một thành viên mới thanh toán tại !!sitename!!.</p>
2
+ <p>Dưới đây là chi tiết về tài khoản thành viên của bạn.</p>
3
+
4
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
5
+ <p>Kiểu thành viên: !!membership_level_name!!</p>
6
+ !!membership_expiration!! !!discount_code!!
7
+
8
+ <p>Đăng nhập để vào tài khoản của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/checkout_freetrial.html ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Cảm ơn bạn đã đang ký thành viên tại !!sitename!!. Tài kh oản thành viên của bạn sẽ được kích hoạt ngay.</p>
2
+ <p>Dưới đây là chi tiết về tài khoản thành viên của bạn.</p>
3
+
4
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
5
+ <p>Kiểu thành viên !!membership_level_name!!</p>
6
+ <p>Phí thành viên: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
+
9
+ <p>
10
+ Thông t in thanh toán trong hồ sơ:<br />
11
+ !!billing_address!!
12
+ </p>
13
+
14
+ <p>
15
+ !!cardtype!!: !!accountnumber!!<br />
16
+ Hết hạn: !!expirationmonth!!/!!expirationyear!!
17
+ </p>
18
+
19
+ <p>Đăng nhập để vào tài khoản của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/checkout_freetrial_admin.html ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Có một thành viên mới thanh toán tại !!sitename!!.</p>
2
+ <p>Dưới đây là chi tiết về tài khoản thành viên của bạn và biên nhận cho hóa đơn cho thành viên lần đầu của bạn.</p>
3
+
4
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
5
+ <p>Kiểu thành viên: !!membership_level_name!!</p>
6
+ <p>Phí thành viên: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
+
9
+ <p>
10
+ Thông t in thanh toán trong hồ sơ:<br />
11
+ !!billing_address!!
12
+ </p>
13
+
14
+ <p>
15
+ !!cardtype!!: !!accountnumber!!<br />
16
+ Hết hạn: !!expirationmonth!!/!!expirationyear!!
17
+ </p>
18
+
19
+ <p>Đăng nhập để vào tài khoản của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/checkout_paid.html ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Cảm ơn bạn đã đang ký thành viên tại !!sitename!!. Tài kh oản thành viên của bạn sẽ được kích hoạt ngay.</p>
2
+ <p>Dưới đây là chi tiết về tài khoản thành viên của bạn và biên nhận cho hóa đơn cho thành viên lần đầu của bạn.</p>
3
+
4
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
5
+ <p>Kiểu thành viên: !!membership_level_name!!</p>
6
+ <p>Phí thành viên: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
+
9
+ <p>
10
+ Số hóa đơn!!invoice_id!! trong !!invoice_date!!<br />
11
+ Hóa đơn tổng: !!invoice_total!!
12
+ </p>
13
+ <p>
14
+ Thông t in thanh toán:<br />
15
+ !!billing_address!!
16
+ </p>
17
+
18
+ <p>
19
+ !!cardtype!!: !!accountnumber!!<br />
20
+ Expires: !!expirationmonth!!/!!expirationyear!!
21
+ </p>
22
+
23
+ <p>Đăng nhập để vào tài khoản của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/checkout_paid_admin.html ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Có một thành viên mới thanh toán tại !!sitename!!.</p>
2
+ <p>Dưới đây là chi tiết về tài khoản thành viên của bạn và biên nhận cho hóa đơn cho thành viên lần đầu của bạn.</p>
3
+
4
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
5
+ <p>Kiểu thành viên: !!membership_level_name!!</p>
6
+ <p>Phí thành viên: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
+
9
+ <p>
10
+ Số hóa đơn!!invoice_id!! trong !!invoice_date!!<br />
11
+ Hóa đơn tổng: !!invoice_total!!
12
+ </p>
13
+ <p>
14
+ Thông tin thanh toán:<br />
15
+ !!billing_address!!
16
+ </p>
17
+
18
+ <p>
19
+ !!cardtype!!: !!accountnumber!!<br />
20
+ Hết hạn: !!expirationmonth!!/!!expirationyear!!
21
+ </p>
22
+
23
+ <p>Đăng nhập để vào tài khoản của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/checkout_trial.html ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 7<p>Cảm ơn bạn đã đang ký thành viên tại !!sitename!!. Tài kh oản thành viên của bạn sẽ được kích hoạt ngay.</p>
2
+ <p>Dưới đây là chi tiết về tài khoản thành viên của bạn và biên nhận cho hóa đơn cho thành viên lần đầu của bạn.</p>
3
+
4
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
5
+ <p>Kiểu thành viên: !!membership_level_name!!</p>
6
+ <p>Phí thành viên: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
+
9
+ <p>
10
+ Số hóa đơn!!invoice_id!! trong !!invoice_date!!<br />
11
+ Hóa đơn tổng: !!invoice_total!!
12
+ </p>
13
+ <p>
14
+ Thông tin thanh toán:<br />
15
+ !!billing_address!!
16
+ </p>
17
+
18
+ <p>
19
+ !!cardtype!!: !!accountnumber!!<br />
20
+ Hết hạn: !!expirationmonth!!/!!expirationyear!!
21
+ </p>
22
+
23
+ <p>Log in to your membership account here: !!login_link!!</p>
languages/email/vi_VN/checkout_trial_admin.html ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Có một thành viên mới thanh toán tại !!sitename!!.</p>
2
+ <p>Dưới đây là chi tiết về tài khoản thành viên của bạn và biên nhận cho hóa đơn cho thành viên lần đầu của bạn.</p>
3
+
4
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
5
+ <p>Kiểu thành viên: !!membership_level_name!!</p>
6
+ <p>Phí thành viên: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
+
9
+ <p>
10
+ Số hóa đơn!!invoice_id!! on !!invoice_date!!<br />
11
+ Hóa đơn tổng: !!invoice_total!!
12
+ </p>
13
+ <p>
14
+ Thông tin thanh toán:<br />
15
+ !!billing_address!!
16
+ </p>
17
+
18
+ <p>
19
+ !!cardtype!!: !!accountnumber!!<br />
20
+ Hết hạn: !!expirationmonth!!/!!expirationyear!!
21
+ </p>
22
+
23
+ <p>Đăng nhập để vào tài khoản của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/credit_card_expiring.html ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Phương thức thanh toán cho tài khoản thành viên tại !!sitename!! sẽ sớm hết hạn. <strong>Vui lòng click vào link dưới đây để đăng nhập và cập nhật thông tin thanh toán của bạn để tránh bị ngừng tài khoản. !!login_link!!</strong></p>
2
+
3
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
4
+ <p>Các thông tin tài khoản gần đây nhất mà chúng tôi có trong hồ sơ is:</p>
5
+
6
+ <p>!!billing_name!!</br />
7
+ !!billing_address!!
8
+ </p>
9
+
10
+ <p>
11
+ !!cardtype!!: !!accountnumber!!<br />
12
+ Hết hạn: !!expirationmonth!!/!!expirationyear!!
13
+ </p>
languages/email/vi_VN/default.html ADDED
@@ -0,0 +1 @@
 
1
+ !!body!!
languages/email/vi_VN/footer.html ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <p>
2
+ Trân trọng,<br />
3
+ !!sitename!!
4
+ </p>
languages/email/vi_VN/header.html ADDED
@@ -0,0 +1 @@
 
1
+ <p>Kính gửi !!name!!,</p>
languages/email/vi_VN/invoice.html ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Cảm ơn bạn đã đang ký thành viên tại !!sitename!!. Dưới đây là hóa đơn cho đăng ký loại thành viên gần đây nhất của bạn.</p>
2
+
3
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
4
+ <p>
5
+ Số hóa đơn!!invoice_id!! trong !!invoice_date!!<br />
6
+ Hóa đơn tổng: !!invoice_total!!
7
+ </p>
8
+ <p>
9
+ Thông tin thanh toán:<br />
10
+ !!billing_address!!
11
+ </p>
12
+
13
+ <p>
14
+ !!cardtype!!: !!accountnumber!!<br />
15
+ Hết hạn: !!expirationmonth!!/!!expirationyear!!
16
+ </p>
17
+
18
+ <p>Đăng nhập để vào tài khoản của bạn ở đây: !!login_link!!</p>
19
+ <p>Để xem một phiên bản trực tuyến của hoá đơn này, click vào đây: !!invoice_link!!</p>
languages/email/vi_VN/membership_expired.html ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <p>Quyền thành viên tại !!sitename!! đã hết hạn.</p>
2
+
3
+ <p>Cám ơn bạn đã ủng hộ.</p>
4
+
5
+ <p>Xem các loại hội viên hiện tại của chúng tôi tại đây: !!levels_link!!</p>
6
+
7
+ <p>Đăng nhập để quản lý tài khoản của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/membership_expiring.html ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <p>Cảm ơn bạn đã đang ký thành viên tại !!sitename!!. Đây chỉ là nhắc nhở rằng quyền thành viên của bạn sẽ kết thúc vào ngày !!enddate!!.</p>
2
+
3
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
4
+ <p>Kiểu thành viên: !!membership_level_name!!</p>
5
+
6
+ <p>Đăng nhập để vào tài khoản của bạn ở đây: !!login_link!!</p>
languages/email/vi_VN/trial_ending.html ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <p>Cảm ơn bạn đã đang ký thành viên tại !!sitename!!. Thời gian dùng thử của bạn đang kết thucd !!trial_end!!.</p>
2
+
3
+ <p>Tài khoản: !!display_name!! (!!user_email!!)</p>
4
+ <p>Kiểu thành viên: !!membership_level_name!!</p>
5
+
6
+ <p>Lệ phí của bạn sẽ được thay đổi từ !!trial_amount!! tới !!billing_amount!! mỗi !!cycle_number!! !!cycle_period!!(s).</p>
7
+
8
+ <p>Đăng nhập để vào tài khoản của bạn ở đây: !!login_link!!</p>
languages/pmpro-vi_VN.mo ADDED
Binary file
languages/pmpro-vi_VN.po ADDED
@@ -0,0 +1,4556 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Hi there! Details on how to help out translating Paid Memberships Pro can be found at:
3
+ # http://www.paidmembershipspro.com/documentation/languages/
4
+ #
5
+ msgid ""
6
+ msgstr ""
7
+ "Project-Id-Version: pmpro\n"
8
+ "POT-Creation-Date: 2015-08-04 10:23-0400\n"
9
+ "PO-Revision-Date: 2015-09-08 12:20+0700\n"
10
+ "Last-Translator: \n"
11
+ "Language-Team: Stranger Studios <jason@strangerstudios.com>\n"
12
+ "MIME-Version: 1.0\n"
13
+ "Content-Type: text/plain; charset=UTF-8\n"
14
+ "Content-Transfer-Encoding: 8bit\n"
15
+ "Language: vi\n"
16
+ "X-Generator: Poedit 1.8.4\n"
17
+
18
+ #: adminpages/addons.php:21 adminpages/advancedsettings.php:5
19
+ #: adminpages/discountcodes.php:5 adminpages/emailsettings.php:5
20
+ #: adminpages/membershiplevels.php:5 adminpages/memberslist-csv.php:5
21
+ #: adminpages/memberslist.php:5 adminpages/orders-csv.php:5 adminpages/orders.php:5
22
+ #: adminpages/pagesettings.php:5 adminpages/paymentsettings.php:5
23
+ #: includes/license.php:36 adminpages/addons.php:5
24
+ msgid "You do not have permissions to perform this action."
25
+ msgstr ""
26
+
27
+ #: adminpages/addons.php:80 adminpages/admin_header.php:170 includes/adminpages.php:52
28
+ #: includes/adminpages.php:146 adminpages/admin_header.php:133
29
+ #: adminpages/admin_header.php:154 includes/adminpages.php:14 includes/adminpages.php:69
30
+ #: includes/adminpages.php:135 includes/adminpages.php:142
31
+ msgid "Add Ons"
32
+ msgstr ""
33
+
34
+ #: adminpages/addons.php:87
35
+ #, php-format
36
+ msgid "Last checked on %s at %s."
37
+ msgstr ""
38
+
39
+ #: adminpages/addons.php:88
40
+ msgid "Check Again"
41
+ msgstr ""
42
+
43
+ #: adminpages/addons.php:92 adminpages/orders.php:605
44
+ msgid "All"
45
+ msgstr ""
46
+
47
+ #: adminpages/addons.php:93
48
+ msgid "Active"
49
+ msgstr ""
50
+
51
+ #: adminpages/addons.php:94
52
+ msgid "Inactive"
53
+ msgstr ""
54
+
55
+ #: adminpages/addons.php:95
56
+ msgid "Update Available"
57
+ msgstr ""
58
+
59
+ #: adminpages/addons.php:96
60
+ msgid "Not Installed"
61
+ msgstr ""
62
+
63
+ #: adminpages/addons.php:109
64
+ msgid "Add On Name"
65
+ msgstr ""
66
+
67
+ #: adminpages/addons.php:110
68
+ msgid "Type"
69
+ msgstr ""
70
+
71
+ #: adminpages/addons.php:111 adminpages/membershiplevels.php:300
72
+ #: adminpages/membershiplevels.php:296 adminpages/membershiplevels.php:298
73
+ msgid "Description"
74
+ msgstr ""
75
+
76
+ #: adminpages/addons.php:134
77
+ msgid "No Add Ons found."
78
+ msgstr ""
79
+
80
+ #: adminpages/addons.php:195 adminpages/addons.php:200 adminpages/addons.php:212
81
+ msgid "Install Now"
82
+ msgstr ""
83
+
84
+ #: adminpages/addons.php:201 adminpages/addons.php:207 adminpages/addons.php:213
85
+ #: adminpages/addons.php:219
86
+ msgid "Download"
87
+ msgstr ""
88
+
89
+ #: adminpages/addons.php:206 adminpages/addons.php:218
90
+ msgid "Update License"
91
+ msgstr ""
92
+
93
+ #: adminpages/addons.php:224
94
+ msgid "Deactivate"
95
+ msgstr ""
96
+
97
+ #: adminpages/addons.php:224
98
+ #, php-format
99
+ msgid "Deactivate %s"
100
+ msgstr ""
101
+
102
+ #: adminpages/addons.php:228
103
+ msgid "Activate"
104
+ msgstr ""
105
+
106
+ #: adminpages/addons.php:228
107
+ #, php-format
108
+ msgid "Activate %s"
109
+ msgstr ""
110
+
111
+ #: adminpages/addons.php:229
112
+ msgid "Delete"
113
+ msgstr ""
114
+
115
+ #: adminpages/addons.php:229
116
+ #, php-format
117
+ msgid "Delete %s"
118
+ msgstr ""
119
+
120
+ #: adminpages/addons.php:239
121
+ msgid "PMPro Free"
122
+ msgstr ""
123
+
124
+ #: adminpages/addons.php:241
125
+ msgid "PMPro Core"
126
+ msgstr ""
127
+
128
+ #: adminpages/addons.php:243
129
+ msgid "PMPro Plus"
130
+ msgstr ""
131
+
132
+ #: adminpages/addons.php:245
133
+ msgid "WordPress.org"
134
+ msgstr ""
135
+
136
+ #: adminpages/addons.php:247
137
+ msgid "N/A"
138
+ msgstr ""
139
+
140
+ #: adminpages/addons.php:256
141
+ #, php-format
142
+ msgid "Version %s"
143
+ msgstr ""
144
+
145
+ #: adminpages/addons.php:261
146
+ #, php-format
147
+ msgid "By %s"
148
+ msgstr ""
149
+
150
+ #: adminpages/addons.php:268
151
+ #, php-format
152
+ msgid "More information about %s"
153
+ msgstr ""
154
+
155
+ #: adminpages/addons.php:270
156
+ msgid "View details"
157
+ msgstr ""
158
+
159
+ #: adminpages/addons.php:275
160
+ msgid "Visit plugin site"
161
+ msgstr ""
162
+
163
+ #: adminpages/admin_header.php:25
164
+ msgid "Add a membership level to get started."
165
+ msgstr ""
166
+
167
+ #: adminpages/admin_header.php:27
168
+ msgid "Set up the membership pages"
169
+ msgstr ""
170
+
171
+ #: adminpages/admin_header.php:29
172
+ msgid "Set up your SSL certificate and payment gateway"
173
+ msgstr ""
174
+
175
+ #: adminpages/admin_header.php:38
176
+ msgid ""
177
+ "The billing details for some of your membership levels is not supported by Stripe."
178
+ msgstr ""
179
+
180
+ #: adminpages/admin_header.php:46
181
+ msgid ""
182
+ "The billing details for this level are not supported by Stripe. Please review the "
183
+ "notes in the Billing Details section below."
184
+ msgstr ""
185
+
186
+ #: adminpages/admin_header.php:50 adminpages/admin_header.php:70
187
+ #: adminpages/admin_header.php:90 adminpages/admin_header.php:111
188
+ msgid "The levels with issues are highlighted below."
189
+ msgstr ""
190
+
191
+ #: adminpages/admin_header.php:52 adminpages/admin_header.php:72
192
+ #: adminpages/admin_header.php:92 adminpages/admin_header.php:113
193
+ msgid "Please edit your levels"
194
+ msgstr ""
195
+
196
+ #: adminpages/admin_header.php:58
197
+ msgid ""
198
+ "The billing details for some of your membership levels is not supported by Payflow."
199
+ msgstr ""
200
+
201
+ #: adminpages/admin_header.php:66
202
+ msgid ""
203
+ "The billing details for this level are not supported by Payflow. Please review the "
204
+ "notes in the Billing Details section below."
205
+ msgstr ""
206
+
207
+ #: adminpages/admin_header.php:78
208
+ msgid ""
209
+ "The billing details for some of your membership levels is not supported by Braintree."
210
+ msgstr ""
211
+
212
+ #: adminpages/admin_header.php:86
213
+ msgid ""
214
+ "The billing details for this level are not supported by Braintree. Please review the "
215
+ "notes in the Billing Details section below."
216
+ msgstr ""
217
+
218
+ #: adminpages/admin_header.php:98
219
+ msgid ""
220
+ "The billing details for some of your membership levels is not supported by "
221
+ "TwoCheckout."
222
+ msgstr ""
223
+
224
+ #: adminpages/admin_header.php:107
225
+ msgid ""
226
+ "The billing details for this level are not supported by 2Checkout. Please review the "
227
+ "notes in the Billing Details section below."
228
+ msgstr ""
229
+
230
+ #: adminpages/admin_header.php:127 adminpages/admin_header.php:106
231
+ msgid "Plugin Support"
232
+ msgstr ""
233
+
234
+ #: adminpages/admin_header.php:127 adminpages/admin_header.php:106
235
+ msgid "User Forum"
236
+ msgstr ""
237
+
238
+ #: adminpages/admin_header.php:150 adminpages/membershiplevels.php:619
239
+ #: adminpages/pagesettings.php:69 includes/adminpages.php:64 includes/adminpages.php:65
240
+ #: includes/adminpages.php:111 adminpages/admin_header.php:128
241
+ #: adminpages/admin_header.php:149 adminpages/membershiplevels.php:490
242
+ #: adminpages/membershiplevels.php:496 adminpages/membershiplevels.php:498
243
+ #: adminpages/membershiplevels.php:525 adminpages/membershiplevels.php:526
244
+ #: adminpages/membershiplevels.php:569 includes/adminpages.php:44
245
+ #: includes/adminpages.php:100 includes/adminpages.php:107
246
+ msgid "Membership Levels"
247
+ msgstr ""
248
+
249
+ #: adminpages/admin_header.php:154 adminpages/pagesettings.php:120
250
+ #: adminpages/admin_header.php:129 adminpages/admin_header.php:150
251
+ #: adminpages/pagesettings.php:92
252
+ msgid "Pages"
253
+ msgstr ""
254
+
255
+ #: adminpages/admin_header.php:158 adminpages/admin_header.php:130
256
+ #: adminpages/admin_header.php:151
257
+ msgid "Payment Gateway &amp; SSL"
258
+ msgstr ""
259
+
260
+ #: adminpages/admin_header.php:162 adminpages/memberslist.php:168
261
+ #: shortcodes/pmpro_account.php:106 adminpages/admin_header.php:131
262
+ #: adminpages/admin_header.php:152 adminpages/memberslist.php:115
263
+ #: adminpages/memberslist.php:148 adminpages/memberslist.php:158 pages/account.php:52
264
+ #: pages/account.php:56 pages/account.php:77
265
+ msgid "Email"
266
+ msgstr ""
267
+
268
+ #: adminpages/admin_header.php:166 adminpages/admin_header.php:132
269
+ #: adminpages/admin_header.php:153
270
+ msgid "Advanced"
271
+ msgstr ""
272
+
273
+ #: adminpages/advancedsettings.php:43 adminpages/advancedsettings.php:35
274
+ #: adminpages/advancedsettings.php:42
275
+ msgid "Your advanced settings have been updated."
276
+ msgstr ""
277
+
278
+ #: adminpages/advancedsettings.php:68 adminpages/advancedsettings.php:66
279
+ #, php-format
280
+ msgid "This content is for !!levels!! members only. <a href=\"%s\">Register here</a>."
281
+ msgstr ""
282
+
283
+ #: adminpages/advancedsettings.php:73 adminpages/advancedsettings.php:71
284
+ #, php-format
285
+ msgid ""
286
+ "Please <a href=\"%s\">login</a> to view this content. (<a href=\"%s\">Register here</"
287
+ "a>.)"
288
+ msgstr ""
289
+
290
+ #: adminpages/advancedsettings.php:78 adminpages/advancedsettings.php:76
291
+ msgid "This content is for members only. Visit the site and log in/register to read."
292
+ msgstr ""
293
+
294
+ #: adminpages/advancedsettings.php:88 includes/adminpages.php:51
295
+ #: includes/adminpages.php:139 adminpages/advancedsettings.php:79
296
+ #: adminpages/advancedsettings.php:86 includes/adminpages.php:13
297
+ #: includes/adminpages.php:64 includes/adminpages.php:128 includes/adminpages.php:135
298
+ msgid "Advanced Settings"
299
+ msgstr ""
300
+
301
+ #: adminpages/advancedsettings.php:94 adminpages/advancedsettings.php:85
302
+ #: adminpages/advancedsettings.php:92
303
+ msgid "Message for Logged-in Non-members"
304
+ msgstr ""
305
+
306
+ #: adminpages/advancedsettings.php:98 adminpages/advancedsettings.php:89
307
+ #: adminpages/advancedsettings.php:96
308
+ msgid "This message replaces the post content for non-members. Available variables"
309
+ msgstr ""
310
+
311
+ #: adminpages/advancedsettings.php:103 adminpages/advancedsettings.php:94
312
+ #: adminpages/advancedsettings.php:101
313
+ msgid "Message for Logged-out Users"
314
+ msgstr ""
315
+
316
+ #: adminpages/advancedsettings.php:107 adminpages/advancedsettings.php:98
317
+ #: adminpages/advancedsettings.php:105
318
+ msgid "This message replaces the post content for logged-out visitors."
319
+ msgstr ""
320
+
321
+ #: adminpages/advancedsettings.php:112 adminpages/advancedsettings.php:103
322
+ #: adminpages/advancedsettings.php:110
323
+ msgid "Message for RSS Feed"
324
+ msgstr ""
325
+
326
+ #: adminpages/advancedsettings.php:116 adminpages/advancedsettings.php:107
327
+ #: adminpages/advancedsettings.php:114
328
+ msgid "This message replaces the post content in RSS feeds."
329
+ msgstr ""
330
+
331
+ #: adminpages/advancedsettings.php:122
332
+ msgid "Filter searches and archives?"
333
+ msgstr ""
334
+
335
+ #: adminpages/advancedsettings.php:126
336
+ msgid "No - Non-members will see restricted posts/pages in searches and archives."
337
+ msgstr ""
338
+
339
+ #: adminpages/advancedsettings.php:127
340
+ msgid "Yes - Only members will see restricted posts/pages in searches and archives."
341
+ msgstr ""
342
+
343
+ #: adminpages/advancedsettings.php:133 adminpages/advancedsettings.php:113
344
+ #: adminpages/advancedsettings.php:120
345
+ msgid "Show Excerpts to Non-Members?"
346
+ msgstr ""
347
+
348
+ #: adminpages/advancedsettings.php:137 adminpages/advancedsettings.php:117
349
+ #: adminpages/advancedsettings.php:124
350
+ msgid "No - Hide excerpts."
351
+ msgstr ""
352
+
353
+ #: adminpages/advancedsettings.php:138 adminpages/advancedsettings.php:118
354
+ #: adminpages/advancedsettings.php:125
355
+ msgid "Yes - Show excerpts."
356
+ msgstr ""
357
+
358
+ #: adminpages/advancedsettings.php:144
359
+ msgid "Hide Ads From Members?"
360
+ msgstr ""
361
+
362
+ #: adminpages/advancedsettings.php:148 adminpages/advancedsettings.php:207
363
+ #: adminpages/advancedsettings.php:219 adminpages/membershiplevels.php:668
364
+ #: adminpages/paymentsettings.php:210 classes/gateways/class.pmprogateway_stripe.php:174
365
+ #: includes/profile.php:105 adminpages/advancedsettings.php:128
366
+ #: adminpages/advancedsettings.php:135 adminpages/advancedsettings.php:187
367
+ #: adminpages/advancedsettings.php:194 adminpages/advancedsettings.php:199
368
+ #: adminpages/advancedsettings.php:206 adminpages/membershiplevels.php:563
369
+ #: adminpages/membershiplevels.php:569 adminpages/membershiplevels.php:571
370
+ #: adminpages/membershiplevels.php:578 adminpages/membershiplevels.php:598
371
+ #: adminpages/membershiplevels.php:658 adminpages/paymentsettings.php:414
372
+ #: adminpages/paymentsettings.php:429 adminpages/paymentsettings.php:434
373
+ #: adminpages/paymentsettings.php:436 adminpages/paymentsettings.php:454
374
+ #: adminpages/paymentsettings.php:459 adminpages/paymentsettings.php:461
375
+ #: classes/gateways/class.pmprogateway_stripe.php:173 includes/profile.php:101
376
+ #: includes/profile.php:121 includes/profile.php:123
377
+ msgid "No"
378
+ msgstr ""
379
+
380
+ #: adminpages/advancedsettings.php:149 adminpages/advancedsettings.php:129
381
+ #: adminpages/advancedsettings.php:136
382
+ msgid "Hide Ads From All Members"
383
+ msgstr ""
384
+
385
+ #: adminpages/advancedsettings.php:150 adminpages/advancedsettings.php:130
386
+ #: adminpages/advancedsettings.php:137
387
+ msgid "Hide Ads From Certain Members"
388
+ msgstr ""
389
+
390
+ #: adminpages/advancedsettings.php:157 adminpages/advancedsettings.php:137
391
+ #: adminpages/advancedsettings.php:144
392
+ msgid "Ads from the following plugins will be automatically turned off"
393
+ msgstr ""
394
+
395
+ #: adminpages/advancedsettings.php:158 adminpages/advancedsettings.php:138
396
+ #: adminpages/advancedsettings.php:145
397
+ msgid "To hide ads in your template code, use code like the following"
398
+ msgstr ""
399
+
400
+ #: adminpages/advancedsettings.php:169 adminpages/advancedsettings.php:149
401
+ #: adminpages/advancedsettings.php:156
402
+ msgid "Choose Levels to Hide Ads From"
403
+ msgstr ""
404
+
405
+ #: adminpages/advancedsettings.php:203 adminpages/advancedsettings.php:183
406
+ #: adminpages/advancedsettings.php:190
407
+ msgid "Redirect all traffic from registration page to /susbcription/?"
408
+ msgstr ""
409
+
410
+ #: adminpages/advancedsettings.php:203 adminpages/advancedsettings.php:183
411
+ #: adminpages/advancedsettings.php:190
412
+ msgid "multisite only"
413
+ msgstr ""
414
+
415
+ #: adminpages/advancedsettings.php:208 adminpages/membershiplevels.php:668
416
+ #: adminpages/paymentsettings.php:211 classes/gateways/class.pmprogateway_stripe.php:175
417
+ #: includes/profile.php:106 adminpages/advancedsettings.php:188
418
+ #: adminpages/advancedsettings.php:195 adminpages/membershiplevels.php:563
419
+ #: adminpages/membershiplevels.php:569 adminpages/membershiplevels.php:571
420
+ #: adminpages/membershiplevels.php:578 adminpages/membershiplevels.php:598
421
+ #: adminpages/membershiplevels.php:658 adminpages/paymentsettings.php:415
422
+ #: adminpages/paymentsettings.php:424 adminpages/paymentsettings.php:430
423
+ #: adminpages/paymentsettings.php:435 adminpages/paymentsettings.php:437
424
+ #: adminpages/paymentsettings.php:455 adminpages/paymentsettings.php:460
425
+ #: adminpages/paymentsettings.php:462 classes/gateways/class.pmprogateway_stripe.php:174
426
+ #: includes/profile.php:102 includes/profile.php:122 includes/profile.php:124
427
+ msgid "Yes"
428
+ msgstr ""
429
+
430
+ #: adminpages/advancedsettings.php:215 adminpages/advancedsettings.php:195
431
+ #: adminpages/advancedsettings.php:202
432
+ msgid "Use reCAPTCHA?"
433
+ msgstr ""
434
+
435
+ #: adminpages/advancedsettings.php:220 adminpages/advancedsettings.php:200
436
+ #: adminpages/advancedsettings.php:207
437
+ msgid "Yes - Free memberships only."
438
+ msgstr ""
439
+
440
+ #: adminpages/advancedsettings.php:221 adminpages/advancedsettings.php:201
441
+ #: adminpages/advancedsettings.php:208
442
+ msgid "Yes - All memberships."
443
+ msgstr ""
444
+
445
+ #: adminpages/advancedsettings.php:223 adminpages/advancedsettings.php:203
446
+ #: adminpages/advancedsettings.php:210
447
+ msgid "A free reCAPTCHA key is required."
448
+ msgstr ""
449
+
450
+ #: adminpages/advancedsettings.php:223 adminpages/advancedsettings.php:203
451
+ #: adminpages/advancedsettings.php:210
452
+ msgid "Click here to signup for reCAPTCHA"
453
+ msgstr ""
454
+
455
+ #: adminpages/advancedsettings.php:229 adminpages/advancedsettings.php:209
456
+ #: adminpages/advancedsettings.php:216
457
+ msgid "reCAPTCHA Public Key"
458
+ msgstr ""
459
+
460
+ #: adminpages/advancedsettings.php:232 adminpages/advancedsettings.php:212
461
+ #: adminpages/advancedsettings.php:219
462
+ msgid "reCAPTCHA Private Key"
463
+ msgstr ""
464
+
465
+ #: adminpages/advancedsettings.php:238 adminpages/advancedsettings.php:218
466
+ #: adminpages/advancedsettings.php:225
467
+ msgid "Require Terms of Service on signups?"
468
+ msgstr ""
469
+
470
+ #: adminpages/advancedsettings.php:245 adminpages/advancedsettings.php:225
471
+ #: adminpages/advancedsettings.php:232
472
+ msgid ""
473
+ "If yes, create a WordPress page containing your TOS agreement and assign it using the "
474
+ "dropdown above."
475
+ msgstr ""
476
+
477
+ #: adminpages/advancedsettings.php:285 adminpages/advancedsettings.php:272
478
+ msgid "selected"
479
+ msgstr ""
480
+
481
+ #: adminpages/advancedsettings.php:368 adminpages/pagesettings.php:251
482
+ #: adminpages/paymentsettings.php:238 adminpages/advancedsettings.php:284
483
+ #: adminpages/advancedsettings.php:355 adminpages/pagesettings.php:209
484
+ #: adminpages/pagesettings.php:223 adminpages/pagesettings.php:254
485
+ #: adminpages/paymentsettings.php:485 adminpages/paymentsettings.php:526
486
+ #: adminpages/paymentsettings.php:532 adminpages/paymentsettings.php:534
487
+ msgid "Save Settings"
488
+ msgstr ""
489
+
490
+ #: adminpages/discountcodes.php:48
491
+ msgid "Discount code updated successfully."
492
+ msgstr ""
493
+
494
+ #: adminpages/discountcodes.php:55
495
+ msgid "Error updating discount code. That code may already be in use."
496
+ msgstr ""
497
+
498
+ #: adminpages/discountcodes.php:64
499
+ msgid "Discount code added successfully."
500
+ msgstr ""
501
+
502
+ #: adminpages/discountcodes.php:72 adminpages/discountcodes.php:71
503
+ msgid "Error adding discount code. That code may already be in use."
504
+ msgstr ""
505
+
506
+ #: adminpages/discountcodes.php:197 adminpages/discountcodes.php:196
507
+ #, php-format
508
+ msgid "Error saving values for the %s level."
509
+ msgstr ""
510
+
511
+ #: adminpages/discountcodes.php:205 adminpages/discountcodes.php:204
512
+ msgid "There were errors updating the level values: "
513
+ msgstr ""
514
+
515
+ #: adminpages/discountcodes.php:238 adminpages/discountcodes.php:234
516
+ #: adminpages/discountcodes.php:237
517
+ #, php-format
518
+ msgid "Code %s deleted successfully."
519
+ msgstr ""
520
+
521
+ #: adminpages/discountcodes.php:243 adminpages/discountcodes.php:239
522
+ #: adminpages/discountcodes.php:242
523
+ msgid ""
524
+ "Error deleting discount code. The code was only partially deleted. Please try again."
525
+ msgstr ""
526
+
527
+ #: adminpages/discountcodes.php:249 adminpages/discountcodes.php:245
528
+ #: adminpages/discountcodes.php:248
529
+ msgid "Error deleting code. Please try again."
530
+ msgstr ""
531
+
532
+ #: adminpages/discountcodes.php:255 adminpages/discountcodes.php:251
533
+ #: adminpages/discountcodes.php:254
534
+ msgid "Code not found."
535
+ msgstr ""
536
+
537
+ #: adminpages/discountcodes.php:268 adminpages/discountcodes.php:264
538
+ #: adminpages/discountcodes.php:267
539
+ msgid "Edit Discount Code"
540
+ msgstr ""
541
+
542
+ #: adminpages/discountcodes.php:270 adminpages/discountcodes.php:558
543
+ #: adminpages/discountcodes.php:266 adminpages/discountcodes.php:269
544
+ #: adminpages/discountcodes.php:526 adminpages/discountcodes.php:529
545
+ #: adminpages/discountcodes.php:557
546
+ msgid "Add New Discount Code"
547
+ msgstr ""
548
+
549
+ #: adminpages/discountcodes.php:310 adminpages/discountcodes.php:586
550
+ #: adminpages/membershiplevels.php:288 adminpages/membershiplevels.php:637
551
+ #: adminpages/memberslist.php:164 adminpages/orders.php:910
552
+ #: adminpages/reports/login.php:142 adminpages/discountcodes.php:306
553
+ #: adminpages/discountcodes.php:309 adminpages/discountcodes.php:547
554
+ #: adminpages/discountcodes.php:557 adminpages/discountcodes.php:585
555
+ #: adminpages/membershiplevels.php:284 adminpages/membershiplevels.php:286
556
+ #: adminpages/membershiplevels.php:505 adminpages/membershiplevels.php:511
557
+ #: adminpages/membershiplevels.php:513 adminpages/membershiplevels.php:540
558
+ #: adminpages/membershiplevels.php:541 adminpages/membershiplevels.php:583
559
+ #: adminpages/memberslist.php:111 adminpages/memberslist.php:144
560
+ #: adminpages/memberslist.php:154 adminpages/orders.php:597 adminpages/orders.php:900
561
+ #: adminpages/reports/login.php:140
562
+ msgid "ID"
563
+ msgstr ""
564
+
565
+ #: adminpages/discountcodes.php:311 adminpages/orders.php:261
566
+ #: adminpages/discountcodes.php:307 adminpages/discountcodes.php:310
567
+ #: adminpages/orders.php:211
568
+ msgid "This will be generated when you save."
569
+ msgstr ""
570
+
571
+ #: adminpages/discountcodes.php:315 adminpages/discountcodes.php:587
572
+ #: adminpages/orders.php:265 adminpages/orders.php:911 adminpages/discountcodes.php:311
573
+ #: adminpages/discountcodes.php:314 adminpages/discountcodes.php:548
574
+ #: adminpages/discountcodes.php:558 adminpages/discountcodes.php:586
575
+ #: adminpages/orders.php:215 adminpages/orders.php:598 adminpages/orders.php:901
576
+ msgid "Code"
577
+ msgstr ""
578
+
579
+ #: adminpages/discountcodes.php:353 adminpages/discountcodes.php:349
580
+ #: adminpages/discountcodes.php:352
581
+ msgid "Start Date"
582
+ msgstr ""
583
+
584
+ #: adminpages/discountcodes.php:371
585
+ #: classes/gateways/class.pmprogateway_braintree.php:321
586
+ #: classes/gateways/class.pmprogateway_stripe.php:455 pages/billing.php:262
587
+ #: pages/checkout.php:562 adminpages/discountcodes.php:367
588
+ #: adminpages/discountcodes.php:370
589
+ #: classes/gateways/class.pmprogateway_braintree.php:308
590
+ #: classes/gateways/class.pmprogateway_stripe.php:454 pages/billing.php:249
591
+ #: pages/billing.php:253 pages/checkout.php:508 pages/checkout.php:524
592
+ #: pages/checkout.php:525 pages/checkout.php:532 pages/checkout.php:553
593
+ msgid "Expiration Date"
594
+ msgstr ""
595
+
596
+ #: adminpages/discountcodes.php:389 adminpages/discountcodes.php:590
597
+ #: adminpages/discountcodes.php:385 adminpages/discountcodes.php:388
598
+ #: adminpages/discountcodes.php:551 adminpages/discountcodes.php:561
599
+ #: adminpages/discountcodes.php:589
600
+ msgid "Uses"
601
+ msgstr ""
602
+
603
+ #: adminpages/discountcodes.php:392 adminpages/discountcodes.php:388
604
+ #: adminpages/discountcodes.php:391
605
+ msgid "Leave blank for unlimited uses."
606
+ msgstr ""
607
+
608
+ #: adminpages/discountcodes.php:401 adminpages/discountcodes.php:400
609
+ msgid "Which Levels Will This Code Apply To?"
610
+ msgstr ""
611
+
612
+ #: adminpages/discountcodes.php:431 adminpages/membershiplevels.php:342
613
+ #: adminpages/discountcodes.php:427 adminpages/discountcodes.php:430
614
+ #: adminpages/membershiplevels.php:337 adminpages/membershiplevels.php:339
615
+ #: adminpages/membershiplevels.php:341 adminpages/membershiplevels.php:507
616
+ #: adminpages/membershiplevels.php:513 adminpages/membershiplevels.php:515
617
+ #: adminpages/membershiplevels.php:542 pages/levels.php:14
618
+ msgid "Initial Payment"
619
+ msgstr ""
620
+
621
+ #: adminpages/discountcodes.php:442 adminpages/membershiplevels.php:353
622
+ #: adminpages/discountcodes.php:428 adminpages/discountcodes.php:431
623
+ #: adminpages/discountcodes.php:441 adminpages/membershiplevels.php:338
624
+ #: adminpages/membershiplevels.php:340 adminpages/membershiplevels.php:350
625
+ #: adminpages/membershiplevels.php:352
626
+ msgid "The initial amount collected at registration."
627
+ msgstr ""
628
+
629
+ #: adminpages/discountcodes.php:447 adminpages/membershiplevels.php:357
630
+ #: adminpages/discountcodes.php:432 adminpages/discountcodes.php:435
631
+ #: adminpages/discountcodes.php:446 adminpages/membershiplevels.php:342
632
+ #: adminpages/membershiplevels.php:344 adminpages/membershiplevels.php:354
633
+ #: adminpages/membershiplevels.php:356
634
+ msgid "Recurring Subscription"
635
+ msgstr ""
636
+
637
+ #: adminpages/discountcodes.php:448 adminpages/membershiplevels.php:358
638
+ #: adminpages/discountcodes.php:433 adminpages/discountcodes.php:436
639
+ #: adminpages/discountcodes.php:447 adminpages/membershiplevels.php:343
640
+ #: adminpages/membershiplevels.php:345 adminpages/membershiplevels.php:355
641
+ #: adminpages/membershiplevels.php:357
642
+ msgid "Check if this level has a recurring subscription payment."
643
+ msgstr ""
644
+
645
+ #: adminpages/discountcodes.php:452 adminpages/membershiplevels.php:362
646
+ #: adminpages/discountcodes.php:440 adminpages/discountcodes.php:451
647
+ #: adminpages/membershiplevels.php:347 adminpages/membershiplevels.php:349
648
+ #: adminpages/membershiplevels.php:359 adminpages/membershiplevels.php:361
649
+ msgid "Billing Amount"
650
+ msgstr ""
651
+
652
+ #: adminpages/discountcodes.php:467 adminpages/discountcodes.php:521
653
+ #: adminpages/membershiplevels.php:377 adminpages/membershiplevels.php:480
654
+ #: classes/gateways/class.pmprogateway_stripe.php:522 adminpages/discountcodes.php:446
655
+ #: adminpages/discountcodes.php:466 adminpages/discountcodes.php:492
656
+ #: adminpages/discountcodes.php:520 adminpages/membershiplevels.php:353
657
+ #: adminpages/membershiplevels.php:355 adminpages/membershiplevels.php:374
658
+ #: adminpages/membershiplevels.php:376 adminpages/membershiplevels.php:449
659
+ #: adminpages/membershiplevels.php:476 adminpages/membershiplevels.php:477
660
+ #: adminpages/membershiplevels.php:479
661
+ #: classes/gateways/class.pmprogateway_stripe.php:521
662
+ msgid "Day(s)"
663
+ msgstr ""
664
+
665
+ #: adminpages/discountcodes.php:467 adminpages/discountcodes.php:521
666
+ #: adminpages/membershiplevels.php:377 adminpages/membershiplevels.php:480
667
+ #: classes/gateways/class.pmprogateway_stripe.php:522 adminpages/discountcodes.php:446
668
+ #: adminpages/discountcodes.php:466 adminpages/discountcodes.php:492
669
+ #: adminpages/discountcodes.php:520 adminpages/membershiplevels.php:353
670
+ #: adminpages/membershiplevels.php:355 adminpages/membershiplevels.php:374
671
+ #: adminpages/membershiplevels.php:376 adminpages/membershiplevels.php:449
672
+ #: adminpages/membershiplevels.php:476 adminpages/membershiplevels.php:477
673
+ #: adminpages/membershiplevels.php:479
674
+ #: classes/gateways/class.pmprogateway_stripe.php:521
675
+ msgid "Month(s)"
676
+ msgstr ""
677
+
678
+ #: adminpages/discountcodes.php:467 adminpages/discountcodes.php:521
679
+ #: adminpages/membershiplevels.php:377 adminpages/membershiplevels.php:480
680
+ #: classes/gateways/class.pmprogateway_stripe.php:522 adminpages/discountcodes.php:446
681
+ #: adminpages/discountcodes.php:466 adminpages/discountcodes.php:492
682
+ #: adminpages/discountcodes.php:520 adminpages/membershiplevels.php:353
683
+ #: adminpages/membershiplevels.php:355 adminpages/membershiplevels.php:374
684
+ #: adminpages/membershiplevels.php:376 adminpages/membershiplevels.php:449
685
+ #: adminpages/membershiplevels.php:476 adminpages/membershiplevels.php:477
686
+ #: adminpages/membershiplevels.php:479
687
+ #: classes/gateways/class.pmprogateway_stripe.php:521
688
+ msgid "Week(s)"
689
+ msgstr ""
690
+
691
+ #: adminpages/discountcodes.php:467 adminpages/discountcodes.php:521
692
+ #: adminpages/membershiplevels.php:377 adminpages/membershiplevels.php:480
693
+ #: classes/gateways/class.pmprogateway_stripe.php:522 adminpages/discountcodes.php:446
694
+ #: adminpages/discountcodes.php:466 adminpages/discountcodes.php:492
695
+ #: adminpages/discountcodes.php:520 adminpages/membershiplevels.php:353
696
+ #: adminpages/membershiplevels.php:355 adminpages/membershiplevels.php:374
697
+ #: adminpages/membershiplevels.php:376 adminpages/membershiplevels.php:449
698
+ #: adminpages/membershiplevels.php:476 adminpages/membershiplevels.php:477
699
+ #: adminpages/membershiplevels.php:479
700
+ #: classes/gateways/class.pmprogateway_stripe.php:521
701
+ msgid "Year(s)"
702
+ msgstr ""
703
+
704
+ #: adminpages/discountcodes.php:475 adminpages/membershiplevels.php:386
705
+ #: adminpages/discountcodes.php:451 adminpages/discountcodes.php:454
706
+ #: adminpages/discountcodes.php:474 adminpages/membershiplevels.php:362
707
+ #: adminpages/membershiplevels.php:364 adminpages/membershiplevels.php:383
708
+ #: adminpages/membershiplevels.php:385
709
+ msgid "The amount to be billed one cycle after the initial payment."
710
+ msgstr ""
711
+
712
+ #: adminpages/discountcodes.php:480 adminpages/membershiplevels.php:404
713
+ #: adminpages/discountcodes.php:456 adminpages/discountcodes.php:459
714
+ #: adminpages/discountcodes.php:479 adminpages/membershiplevels.php:380
715
+ #: adminpages/membershiplevels.php:382 adminpages/membershiplevels.php:401
716
+ #: adminpages/membershiplevels.php:403
717
+ msgid "Billing Cycle Limit"
718
+ msgstr ""
719
+
720
+ #: adminpages/discountcodes.php:483 adminpages/membershiplevels.php:408
721
+ #: adminpages/discountcodes.php:459 adminpages/discountcodes.php:462
722
+ #: adminpages/discountcodes.php:482 adminpages/membershiplevels.php:384
723
+ #: adminpages/membershiplevels.php:386 adminpages/membershiplevels.php:405
724
+ #: adminpages/membershiplevels.php:407
725
+ msgid ""
726
+ "The <strong>total</strong> number of recurring billing cycles for this level, "
727
+ "including the trial period (if applicable) but not including the initial payment. Set "
728
+ "to zero if membership is indefinite."
729
+ msgstr ""
730
+
731
+ #: adminpages/discountcodes.php:488 adminpages/membershiplevels.php:417
732
+ #: adminpages/discountcodes.php:464 adminpages/discountcodes.php:467
733
+ #: adminpages/discountcodes.php:487 adminpages/membershiplevels.php:393
734
+ #: adminpages/membershiplevels.php:395 adminpages/membershiplevels.php:414
735
+ #: adminpages/membershiplevels.php:416
736
+ msgid "Custom Trial"
737
+ msgstr ""
738
+
739
+ #: adminpages/discountcodes.php:489 adminpages/membershiplevels.php:419
740
+ #: adminpages/discountcodes.php:465 adminpages/discountcodes.php:468
741
+ #: adminpages/discountcodes.php:488 adminpages/membershiplevels.php:394
742
+ #: adminpages/membershiplevels.php:395 adminpages/membershiplevels.php:397
743
+ #: adminpages/membershiplevels.php:416 adminpages/membershiplevels.php:418
744
+ msgid "Check to add a custom trial period."
745
+ msgstr ""
746
+
747
+ #: adminpages/discountcodes.php:493 adminpages/membershiplevels.php:428
748
+ #: adminpages/discountcodes.php:469 adminpages/discountcodes.php:472
749
+ #: adminpages/discountcodes.php:492 adminpages/membershiplevels.php:398
750
+ #: adminpages/membershiplevels.php:404 adminpages/membershiplevels.php:406
751
+ #: adminpages/membershiplevels.php:425 adminpages/membershiplevels.php:427
752
+ msgid "Trial Billing Amount"
753
+ msgstr ""
754
+
755
+ #: adminpages/discountcodes.php:504 adminpages/membershiplevels.php:439
756
+ #: adminpages/discountcodes.php:472 adminpages/discountcodes.php:475
757
+ #: adminpages/discountcodes.php:503 adminpages/membershiplevels.php:401
758
+ #: adminpages/membershiplevels.php:407 adminpages/membershiplevels.php:409
759
+ #: adminpages/membershiplevels.php:436 adminpages/membershiplevels.php:438
760
+ msgid "for the first"
761
+ msgstr ""
762
+
763
+ #: adminpages/discountcodes.php:506 adminpages/membershiplevels.php:441
764
+ #: adminpages/discountcodes.php:474 adminpages/discountcodes.php:477
765
+ #: adminpages/discountcodes.php:505 adminpages/membershiplevels.php:403
766
+ #: adminpages/membershiplevels.php:409 adminpages/membershiplevels.php:411
767
+ #: adminpages/membershiplevels.php:438 adminpages/membershiplevels.php:440
768
+ msgid "subscription payments"
769
+ msgstr ""
770
+
771
+ #: adminpages/discountcodes.php:511 adminpages/membershiplevels.php:470
772
+ #: adminpages/discountcodes.php:479 adminpages/discountcodes.php:482
773
+ #: adminpages/discountcodes.php:510 adminpages/membershiplevels.php:431
774
+ #: adminpages/membershiplevels.php:437 adminpages/membershiplevels.php:439
775
+ #: adminpages/membershiplevels.php:466 adminpages/membershiplevels.php:467
776
+ #: adminpages/membershiplevels.php:469
777
+ msgid "Membership Expiration"
778
+ msgstr ""
779
+
780
+ #: adminpages/discountcodes.php:512 adminpages/membershiplevels.php:471
781
+ #: adminpages/discountcodes.php:483 adminpages/discountcodes.php:511
782
+ #: adminpages/membershiplevels.php:432 adminpages/membershiplevels.php:438
783
+ #: adminpages/membershiplevels.php:440 adminpages/membershiplevels.php:467
784
+ #: adminpages/membershiplevels.php:468 adminpages/membershiplevels.php:470
785
+ msgid "Check this to set when membership access expires."
786
+ msgstr ""
787
+
788
+ #: adminpages/discountcodes.php:516 adminpages/membershiplevels.php:475
789
+ #: adminpages/discountcodes.php:484 adminpages/discountcodes.php:487
790
+ #: adminpages/discountcodes.php:515 adminpages/membershiplevels.php:436
791
+ #: adminpages/membershiplevels.php:442 adminpages/membershiplevels.php:444
792
+ #: adminpages/membershiplevels.php:471 adminpages/membershiplevels.php:472
793
+ #: adminpages/membershiplevels.php:474
794
+ msgid "Expires In"
795
+ msgstr ""
796
+
797
+ #: adminpages/discountcodes.php:529 adminpages/membershiplevels.php:488
798
+ #: adminpages/discountcodes.php:500 adminpages/discountcodes.php:528
799
+ #: adminpages/membershiplevels.php:449 adminpages/membershiplevels.php:455
800
+ #: adminpages/membershiplevels.php:457 adminpages/membershiplevels.php:484
801
+ #: adminpages/membershiplevels.php:485 adminpages/membershiplevels.php:487
802
+ msgid ""
803
+ "Set the duration of membership access. Note that the any future payments (recurring "
804
+ "subscription, if any) will be cancelled when the membership expires."
805
+ msgstr ""
806
+
807
+ #: adminpages/discountcodes.php:557 adminpages/discountcodes.php:525
808
+ #: adminpages/discountcodes.php:528 adminpages/discountcodes.php:556
809
+ msgid "Memberships Discount Codes"
810
+ msgstr ""
811
+
812
+ #: adminpages/discountcodes.php:567 adminpages/discountcodes.php:535
813
+ #: adminpages/discountcodes.php:538 adminpages/discountcodes.php:566
814
+ msgid "Search Discount Codes"
815
+ msgstr ""
816
+
817
+ #: adminpages/discountcodes.php:570 adminpages/reports/login.php:83
818
+ #: adminpages/discountcodes.php:538 adminpages/discountcodes.php:541
819
+ #: adminpages/discountcodes.php:569 adminpages/reports/login.php:81
820
+ msgid "Search"
821
+ msgstr ""
822
+
823
+ #: adminpages/discountcodes.php:588 adminpages/discountcodes.php:549
824
+ #: adminpages/discountcodes.php:559 adminpages/discountcodes.php:587
825
+ msgid "Starts"
826
+ msgstr ""
827
+
828
+ #: adminpages/discountcodes.php:589 adminpages/memberslist.php:179
829
+ #: adminpages/reports/login.php:147 includes/profile.php:102
830
+ #: adminpages/discountcodes.php:550 adminpages/discountcodes.php:560
831
+ #: adminpages/discountcodes.php:588 adminpages/memberslist.php:121
832
+ #: adminpages/memberslist.php:159 adminpages/memberslist.php:169
833
+ #: adminpages/reports/login.php:145 includes/profile.php:98 includes/profile.php:118
834
+ #: includes/profile.php:120
835
+ msgid "Expires"
836
+ msgstr ""
837
+
838
+ #: adminpages/discountcodes.php:591 adminpages/discountcodes.php:552
839
+ #: adminpages/discountcodes.php:562 adminpages/discountcodes.php:590
840
+ msgid "Levels"
841
+ msgstr ""
842
+
843
+ #: adminpages/discountcodes.php:603 adminpages/discountcodes.php:570
844
+ #: adminpages/discountcodes.php:574 adminpages/discountcodes.php:602
845
+ msgid "Create your first discount code now"
846
+ msgstr ""
847
+
848
+ #: adminpages/discountcodes.php:603 adminpages/discountcodes.php:570
849
+ #: adminpages/discountcodes.php:574 adminpages/discountcodes.php:602
850
+ msgid ""
851
+ "Discount codes allow you to offer your memberships at discounted prices to select "
852
+ "customers."
853
+ msgstr ""
854
+
855
+ #: adminpages/discountcodes.php:649 adminpages/membershiplevels.php:670
856
+ #: adminpages/orders.php:992 adminpages/discountcodes.php:614
857
+ #: adminpages/discountcodes.php:619 adminpages/discountcodes.php:647
858
+ #: adminpages/discountcodes.php:648 adminpages/membershiplevels.php:564
859
+ #: adminpages/membershiplevels.php:570 adminpages/membershiplevels.php:572
860
+ #: adminpages/membershiplevels.php:580 adminpages/membershiplevels.php:599
861
+ #: adminpages/membershiplevels.php:660 adminpages/orders.php:658
862
+ #: adminpages/orders.php:961 adminpages/orders.php:979 adminpages/orders.php:989
863
+ msgid "edit"
864
+ msgstr ""
865
+
866
+ #: adminpages/discountcodes.php:652 adminpages/discountcodes.php:617
867
+ #: adminpages/discountcodes.php:622 adminpages/discountcodes.php:650
868
+ #: adminpages/discountcodes.php:651
869
+ #, php-format
870
+ msgid ""
871
+ "Are you sure you want to delete the %s discount code? The subscriptions for existing "
872
+ "users will not change, but new users will not be able to use this code anymore."
873
+ msgstr ""
874
+
875
+ #: adminpages/discountcodes.php:652 adminpages/membershiplevels.php:670
876
+ #: adminpages/orders.php:998 adminpages/discountcodes.php:617
877
+ #: adminpages/discountcodes.php:622 adminpages/discountcodes.php:650
878
+ #: adminpages/discountcodes.php:651 adminpages/membershiplevels.php:566
879
+ #: adminpages/membershiplevels.php:572 adminpages/membershiplevels.php:574
880
+ #: adminpages/membershiplevels.php:580 adminpages/membershiplevels.php:601
881
+ #: adminpages/membershiplevels.php:660 adminpages/orders.php:664
882
+ #: adminpages/orders.php:967 adminpages/orders.php:985 adminpages/orders.php:995
883
+ msgid "delete"
884
+ msgstr ""
885
+
886
+ #: adminpages/emailsettings.php:69 includes/adminpages.php:50
887
+ #: includes/adminpages.php:132 adminpages/emailsettings.php:60
888
+ #: includes/adminpages.php:12 includes/adminpages.php:59 includes/adminpages.php:121
889
+ #: includes/adminpages.php:128
890
+ msgid "Email Settings"
891
+ msgstr ""
892
+
893
+ #: adminpages/emailsettings.php:70 adminpages/emailsettings.php:61
894
+ msgid ""
895
+ "By default, system generated emails are sent from <em><strong>wordpress@yourdomain."
896
+ "com</strong></em>. You can update this from address using the fields below."
897
+ msgstr ""
898
+
899
+ #: adminpages/emailsettings.php:72 adminpages/emailsettings.php:63
900
+ msgid ""
901
+ "To modify the appearance of system generated emails, add the files <em>email_header."
902
+ "html</em> and <em>email_footer.html</em> to your theme's directory. This will modify "
903
+ "both the WordPress default messages as well as messages generated by Paid Memberships "
904
+ "Pro. <a title=\"Paid Memberships Pro - Member Communications\" target=\"_blank\" href="
905
+ "\"http://www.paidmembershipspro.com/documentation/member-communications/\">Click here "
906
+ "to learn more about Paid Memberships Pro emails</a>."
907
+ msgstr ""
908
+
909
+ #: adminpages/emailsettings.php:78 adminpages/emailsettings.php:69
910
+ msgid "From Email"
911
+ msgstr ""
912
+
913
+ #: adminpages/emailsettings.php:86 adminpages/emailsettings.php:77
914
+ msgid "From Name"
915
+ msgstr ""
916
+
917
+ #: adminpages/emailsettings.php:94
918
+ msgid "Only Filter PMPro Emails?"
919
+ msgstr ""
920
+
921
+ #: adminpages/emailsettings.php:98
922
+ msgid "If unchecked, all emails from \"WordPress &lt;"
923
+ msgstr ""
924
+
925
+ #: adminpages/emailsettings.php:115 adminpages/emailsettings.php:86
926
+ #: adminpages/emailsettings.php:104
927
+ msgid "Send the site admin emails"
928
+ msgstr ""
929
+
930
+ #: adminpages/emailsettings.php:121 adminpages/emailsettings.php:92
931
+ #: adminpages/emailsettings.php:110
932
+ msgid "Checkout"
933
+ msgstr ""
934
+
935
+ #: adminpages/emailsettings.php:125 adminpages/emailsettings.php:96
936
+ #: adminpages/emailsettings.php:114
937
+ msgid "when a member checks out."
938
+ msgstr ""
939
+
940
+ #: adminpages/emailsettings.php:130 adminpages/emailsettings.php:101
941
+ #: adminpages/emailsettings.php:119
942
+ msgid "Admin Changes"
943
+ msgstr ""
944
+
945
+ #: adminpages/emailsettings.php:134 adminpages/emailsettings.php:105
946
+ #: adminpages/emailsettings.php:123
947
+ msgid "when an admin changes a user's membership level through the dashboard."
948
+ msgstr ""
949
+
950
+ #: adminpages/emailsettings.php:139 adminpages/emailsettings.php:110
951
+ #: adminpages/emailsettings.php:128
952
+ msgid "Cancellation"
953
+ msgstr ""
954
+
955
+ #: adminpages/emailsettings.php:143 adminpages/emailsettings.php:114
956
+ #: adminpages/emailsettings.php:132
957
+ msgid "when a user cancels his or her account."
958
+ msgstr ""
959
+
960
+ #: adminpages/emailsettings.php:148 adminpages/emailsettings.php:119
961
+ #: adminpages/emailsettings.php:137
962
+ msgid "Bill Updates"
963
+ msgstr ""
964
+
965
+ #: adminpages/emailsettings.php:152 adminpages/emailsettings.php:123
966
+ #: adminpages/emailsettings.php:141
967
+ msgid "when a user updates his or her billing information."
968
+ msgstr ""
969
+
970
+ #: adminpages/emailsettings.php:158 adminpages/emailsettings.php:129
971
+ #: adminpages/emailsettings.php:147
972
+ msgid "Send members emails"
973
+ msgstr ""
974
+
975
+ #: adminpages/emailsettings.php:164 adminpages/emailsettings.php:135
976
+ #: adminpages/emailsettings.php:153
977
+ msgid "New Users"
978
+ msgstr ""
979
+
980
+ #: adminpages/emailsettings.php:168 adminpages/emailsettings.php:139
981
+ #: adminpages/emailsettings.php:157
982
+ msgid ""
983
+ "Default WP notification email. (Recommended: Leave unchecked. Members will still get "
984
+ "an email confirmation from PMPro after checkout.)"
985
+ msgstr ""
986
+
987
+ #: adminpages/membershiplevels.php:120 adminpages/membershiplevels.php:118
988
+ msgid "Membership level updated successfully."
989
+ msgstr ""
990
+
991
+ #: adminpages/membershiplevels.php:126 adminpages/membershiplevels.php:124
992
+ msgid "Error updating membership level."
993
+ msgstr ""
994
+
995
+ #: adminpages/membershiplevels.php:143 adminpages/membershiplevels.php:141
996
+ msgid "Membership level added successfully."
997
+ msgstr ""
998
+
999
+ #: adminpages/membershiplevels.php:148 adminpages/membershiplevels.php:146
1000
+ msgid "Error adding membership level."
1001
+ msgstr ""
1002
+
1003
+ #: adminpages/membershiplevels.php:183 adminpages/membershiplevels.php:179
1004
+ #: adminpages/membershiplevels.php:181
1005
+ #, php-format
1006
+ msgid ""
1007
+ "There was an error canceling the subscription for user with ID=%d. You will want to "
1008
+ "check your payment gateway to see if their subscription is still active."
1009
+ msgstr ""
1010
+
1011
+ #: adminpages/membershiplevels.php:186 adminpages/membershiplevels.php:182
1012
+ #: adminpages/membershiplevels.php:184
1013
+ msgid "Last Invoice"
1014
+ msgstr ""
1015
+
1016
+ #: adminpages/membershiplevels.php:200 adminpages/membershiplevels.php:196
1017
+ #: adminpages/membershiplevels.php:198
1018
+ msgid "Membership level deleted successfully."
1019
+ msgstr ""
1020
+
1021
+ #: adminpages/membershiplevels.php:205 adminpages/membershiplevels.php:211
1022
+ #: adminpages/membershiplevels.php:201 adminpages/membershiplevels.php:203
1023
+ #: adminpages/membershiplevels.php:207 adminpages/membershiplevels.php:209
1024
+ msgid "Error deleting membership level."
1025
+ msgstr ""
1026
+
1027
+ #: adminpages/membershiplevels.php:226 adminpages/membershiplevels.php:222
1028
+ #: adminpages/membershiplevels.php:224
1029
+ msgid "Edit Membership Level"
1030
+ msgstr ""
1031
+
1032
+ #: adminpages/membershiplevels.php:228 adminpages/membershiplevels.php:224
1033
+ #: adminpages/membershiplevels.php:226
1034
+ msgid "Add New Membership Level"
1035
+ msgstr ""
1036
+
1037
+ #: adminpages/membershiplevels.php:295 adminpages/membershiplevels.php:638
1038
+ #: adminpages/reports/login.php:144 adminpages/membershiplevels.php:291
1039
+ #: adminpages/membershiplevels.php:293 adminpages/membershiplevels.php:506
1040
+ #: adminpages/membershiplevels.php:512 adminpages/membershiplevels.php:514
1041
+ #: adminpages/membershiplevels.php:541 adminpages/membershiplevels.php:542
1042
+ #: adminpages/membershiplevels.php:584 adminpages/reports/login.php:142
1043
+ msgid "Name"
1044
+ msgstr ""
1045
+
1046
+ #: adminpages/membershiplevels.php:318 adminpages/membershiplevels.php:314
1047
+ #: adminpages/membershiplevels.php:316
1048
+ msgid "Confirmation Message"
1049
+ msgstr ""
1050
+
1051
+ #: adminpages/membershiplevels.php:338 adminpages/membershiplevels.php:639
1052
+ #: adminpages/membershiplevels.php:333 adminpages/membershiplevels.php:335
1053
+ #: adminpages/membershiplevels.php:337 adminpages/membershiplevels.php:543
1054
+ #: adminpages/membershiplevels.php:585
1055
+ msgid "Billing Details"
1056
+ msgstr ""
1057
+
1058
+ #: adminpages/membershiplevels.php:373
1059
+ #: classes/gateways/class.pmprogateway_stripe.php:620
1060
+ #: adminpages/membershiplevels.php:349 adminpages/membershiplevels.php:351
1061
+ #: adminpages/membershiplevels.php:370 adminpages/membershiplevels.php:372
1062
+ #: classes/gateways/class.pmprogateway_stripe.php:619
1063
+ msgid "per"
1064
+ msgstr ""
1065
+
1066
+ #: adminpages/membershiplevels.php:388 adminpages/membershiplevels.php:366
1067
+ #: adminpages/membershiplevels.php:385 adminpages/membershiplevels.php:387
1068
+ msgid ""
1069
+ "Stripe integration currently only supports billing periods of \"Week\", \"Month\" or "
1070
+ "\"Year\"."
1071
+ msgstr ""
1072
+
1073
+ #: adminpages/membershiplevels.php:390 adminpages/membershiplevels.php:366
1074
+ #: adminpages/membershiplevels.php:368 adminpages/membershiplevels.php:387
1075
+ #: adminpages/membershiplevels.php:389
1076
+ msgid ""
1077
+ "Braintree integration currently only supports billing periods of \"Month\" or \"Year"
1078
+ "\"."
1079
+ msgstr ""
1080
+
1081
+ #: adminpages/membershiplevels.php:392 adminpages/membershiplevels.php:368
1082
+ #: adminpages/membershiplevels.php:370 adminpages/membershiplevels.php:389
1083
+ #: adminpages/membershiplevels.php:391
1084
+ msgid ""
1085
+ "Payflow integration currently only supports billing frequencies of 1 and billing "
1086
+ "periods of \"Week\", \"Month\" or \"Year\"."
1087
+ msgstr ""
1088
+
1089
+ #: adminpages/membershiplevels.php:396 adminpages/membershiplevels.php:372
1090
+ #: adminpages/membershiplevels.php:374 adminpages/membershiplevels.php:393
1091
+ #: adminpages/membershiplevels.php:395
1092
+ msgid ""
1093
+ "After saving this level, make note of the ID and create a \"Plan\" in your Braintree "
1094
+ "dashboard with the same settings and the \"Plan ID\" set to <em>pmpro_#</em>, where # "
1095
+ "is the level ID."
1096
+ msgstr ""
1097
+
1098
+ #: adminpages/membershiplevels.php:396 adminpages/membershiplevels.php:398
1099
+ #: classes/gateways/class.pmprogateway_cybersource.php:101
1100
+ #: classes/gateways/class.pmprogateway_paypal.php:118
1101
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:133
1102
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:117
1103
+ #: adminpages/membershiplevels.php:372 adminpages/membershiplevels.php:374
1104
+ #: adminpages/membershiplevels.php:376 adminpages/membershiplevels.php:393
1105
+ #: adminpages/membershiplevels.php:395 adminpages/membershiplevels.php:397
1106
+ #: adminpages/paymentsettings.php:170 adminpages/paymentsettings.php:174
1107
+ #: adminpages/paymentsettings.php:179
1108
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:123
1109
+ msgid "Note"
1110
+ msgstr ""
1111
+
1112
+ #: adminpages/membershiplevels.php:398 adminpages/membershiplevels.php:374
1113
+ #: adminpages/membershiplevels.php:376 adminpages/membershiplevels.php:395
1114
+ #: adminpages/membershiplevels.php:397
1115
+ msgid ""
1116
+ "You will need to create a \"Plan\" in your Braintree dashboard with the same settings "
1117
+ "and the \"Plan ID\" set to"
1118
+ msgstr ""
1119
+
1120
+ #: adminpages/membershiplevels.php:410 adminpages/membershiplevels.php:386
1121
+ #: adminpages/membershiplevels.php:388 adminpages/membershiplevels.php:407
1122
+ #: adminpages/membershiplevels.php:409
1123
+ msgid ""
1124
+ "Stripe integration currently does not support billing limits. You can still set an "
1125
+ "expiration date below."
1126
+ msgstr ""
1127
+
1128
+ #: adminpages/membershiplevels.php:422 adminpages/membershiplevels.php:398
1129
+ #: adminpages/membershiplevels.php:400 adminpages/membershiplevels.php:419
1130
+ #: adminpages/membershiplevels.php:421
1131
+ msgid ""
1132
+ "2Checkout integration does not support custom trials. You can do one period trials by "
1133
+ "setting an initial payment different from the billing amount."
1134
+ msgstr ""
1135
+
1136
+ #: adminpages/membershiplevels.php:444 adminpages/membershiplevels.php:406
1137
+ #: adminpages/membershiplevels.php:412 adminpages/membershiplevels.php:414
1138
+ #: adminpages/membershiplevels.php:441 adminpages/membershiplevels.php:443
1139
+ msgid "Stripe integration currently does not support trial amounts greater than $0."
1140
+ msgstr ""
1141
+
1142
+ #: adminpages/membershiplevels.php:448 adminpages/membershiplevels.php:410
1143
+ #: adminpages/membershiplevels.php:416 adminpages/membershiplevels.php:418
1144
+ #: adminpages/membershiplevels.php:445 adminpages/membershiplevels.php:447
1145
+ msgid "Braintree integration currently does not support trial amounts greater than $0."
1146
+ msgstr ""
1147
+
1148
+ #: adminpages/membershiplevels.php:452 adminpages/membershiplevels.php:414
1149
+ #: adminpages/membershiplevels.php:420 adminpages/membershiplevels.php:422
1150
+ #: adminpages/membershiplevels.php:449 adminpages/membershiplevels.php:451
1151
+ msgid "Payflow integration currently does not support trial amounts greater than $0."
1152
+ msgstr ""
1153
+
1154
+ #: adminpages/membershiplevels.php:461 adminpages/membershiplevels.php:422
1155
+ #: adminpages/membershiplevels.php:428 adminpages/membershiplevels.php:430
1156
+ #: adminpages/membershiplevels.php:457 adminpages/membershiplevels.php:458
1157
+ #: adminpages/membershiplevels.php:460
1158
+ msgid "Other Settings"
1159
+ msgstr ""
1160
+
1161
+ #: adminpages/membershiplevels.php:465 adminpages/membershiplevels.php:426
1162
+ #: adminpages/membershiplevels.php:432 adminpages/membershiplevels.php:434
1163
+ #: adminpages/membershiplevels.php:461 adminpages/membershiplevels.php:462
1164
+ #: adminpages/membershiplevels.php:464
1165
+ msgid "Disable New Signups"
1166
+ msgstr ""
1167
+
1168
+ #: adminpages/membershiplevels.php:466 adminpages/membershiplevels.php:427
1169
+ #: adminpages/membershiplevels.php:433 adminpages/membershiplevels.php:435
1170
+ #: adminpages/membershiplevels.php:462 adminpages/membershiplevels.php:463
1171
+ #: adminpages/membershiplevels.php:465
1172
+ msgid ""
1173
+ "Check to hide this level from the membership levels page and disable registration."
1174
+ msgstr ""
1175
+
1176
+ #: adminpages/membershiplevels.php:496 adminpages/membershiplevels.php:457
1177
+ #: adminpages/membershiplevels.php:463 adminpages/membershiplevels.php:465
1178
+ #: adminpages/membershiplevels.php:492 adminpages/membershiplevels.php:493
1179
+ #: adminpages/membershiplevels.php:495
1180
+ msgid "Content Settings"
1181
+ msgstr ""
1182
+
1183
+ #: adminpages/membershiplevels.php:500 adminpages/membershiplevels.php:461
1184
+ #: adminpages/membershiplevels.php:467 adminpages/membershiplevels.php:469
1185
+ #: adminpages/membershiplevels.php:496 adminpages/membershiplevels.php:497
1186
+ #: adminpages/membershiplevels.php:499
1187
+ msgid "Categories"
1188
+ msgstr ""
1189
+
1190
+ #: adminpages/membershiplevels.php:517 adminpages/membershiplevels.php:516
1191
+ msgid "Save Level"
1192
+ msgstr ""
1193
+
1194
+ #: adminpages/membershiplevels.php:518 adminpages/orders.php:561 pages/billing.php:339
1195
+ #: pages/cancel.php:71 shortcodes/pmpro_account.php:70
1196
+ #: adminpages/membershiplevels.php:517 adminpages/orders.php:511 pages/account.php:44
1197
+ #: pages/billing.php:295 pages/billing.php:299 pages/billing.php:330
1198
+ msgid "Cancel"
1199
+ msgstr ""
1200
+
1201
+ #: adminpages/membershiplevels.php:619 adminpages/membershiplevels.php:490
1202
+ #: adminpages/membershiplevels.php:496 adminpages/membershiplevels.php:498
1203
+ #: adminpages/membershiplevels.php:525 adminpages/membershiplevels.php:526
1204
+ #: adminpages/membershiplevels.php:569
1205
+ msgid "Add New Level"
1206
+ msgstr ""
1207
+
1208
+ #: adminpages/membershiplevels.php:622 adminpages/membershiplevels.php:625
1209
+ #: adminpages/membershiplevels.php:493 adminpages/membershiplevels.php:496
1210
+ #: adminpages/membershiplevels.php:499 adminpages/membershiplevels.php:501
1211
+ #: adminpages/membershiplevels.php:502 adminpages/membershiplevels.php:504
1212
+ #: adminpages/membershiplevels.php:528 adminpages/membershiplevels.php:529
1213
+ #: adminpages/membershiplevels.php:531 adminpages/membershiplevels.php:532
1214
+ #: adminpages/membershiplevels.php:572 adminpages/membershiplevels.php:575
1215
+ msgid "Search Levels"
1216
+ msgstr ""
1217
+
1218
+ #: adminpages/membershiplevels.php:631 adminpages/membershiplevels.php:579
1219
+ msgid "Drag and drop membership levels to reorder them on the Levels page."
1220
+ msgstr ""
1221
+
1222
+ #: adminpages/membershiplevels.php:640 pages/cancel.php:53 pages/confirmation.php:83
1223
+ #: pages/invoice.php:70 shortcodes/pmpro_account.php:46
1224
+ #: adminpages/membershiplevels.php:510 adminpages/membershiplevels.php:516
1225
+ #: adminpages/membershiplevels.php:518 adminpages/membershiplevels.php:544
1226
+ #: adminpages/membershiplevels.php:545 adminpages/membershiplevels.php:586
1227
+ #: pages/account.php:20 pages/confirmation.php:81 pages/invoice.php:68
1228
+ msgid "Expiration"
1229
+ msgstr ""
1230
+
1231
+ #: adminpages/membershiplevels.php:641 adminpages/membershiplevels.php:511
1232
+ #: adminpages/membershiplevels.php:517 adminpages/membershiplevels.php:519
1233
+ #: adminpages/membershiplevels.php:545 adminpages/membershiplevels.php:546
1234
+ #: adminpages/membershiplevels.php:587
1235
+ msgid "Allow Signups"
1236
+ msgstr ""
1237
+
1238
+ #: adminpages/membershiplevels.php:656 adminpages/membershiplevels.php:534
1239
+ #: adminpages/membershiplevels.php:540 adminpages/membershiplevels.php:542
1240
+ #: adminpages/membershiplevels.php:566 adminpages/membershiplevels.php:569
1241
+ #: adminpages/membershiplevels.php:646
1242
+ msgid "FREE"
1243
+ msgstr ""
1244
+
1245
+ #: adminpages/membershiplevels.php:665 adminpages/membershiplevels.php:560
1246
+ #: adminpages/membershiplevels.php:566 adminpages/membershiplevels.php:568
1247
+ #: adminpages/membershiplevels.php:575 adminpages/membershiplevels.php:595
1248
+ #: adminpages/membershiplevels.php:655
1249
+ msgid "After"
1250
+ msgstr ""
1251
+
1252
+ #: adminpages/membershiplevels.php:670 adminpages/orders.php:995
1253
+ #: adminpages/membershiplevels.php:565 adminpages/membershiplevels.php:571
1254
+ #: adminpages/membershiplevels.php:573 adminpages/membershiplevels.php:580
1255
+ #: adminpages/membershiplevels.php:600 adminpages/membershiplevels.php:660
1256
+ #: adminpages/orders.php:661 adminpages/orders.php:964 adminpages/orders.php:982
1257
+ #: adminpages/orders.php:992
1258
+ msgid "copy"
1259
+ msgstr ""
1260
+
1261
+ #: adminpages/memberslist.php:25 includes/adminpages.php:53 includes/adminpages.php:153
1262
+ #: includes/adminpages.php:15 includes/adminpages.php:74 includes/adminpages.php:142
1263
+ #: includes/adminpages.php:149
1264
+ msgid "Members List"
1265
+ msgstr ""
1266
+
1267
+ #: adminpages/memberslist.php:26 adminpages/orders.php:591 adminpages/orders.php:522
1268
+ msgid "Export to CSV"
1269
+ msgstr ""
1270
+
1271
+ #: adminpages/memberslist.php:30 adminpages/orders.php:603
1272
+ #: adminpages/reports/login.php:67 adminpages/reports/memberships.php:292
1273
+ #: adminpages/reports/sales.php:193 adminpages/reports/login.php:65
1274
+ #: adminpages/reports/sales.php:185 adminpages/reports/sales.php:194
1275
+ msgid "Show"
1276
+ msgstr ""
1277
+
1278
+ #: adminpages/memberslist.php:32 adminpages/reports/login.php:69
1279
+ #: adminpages/reports/memberships.php:317 adminpages/reports/sales.php:216
1280
+ #: adminpages/reports/login.php:67 adminpages/reports/sales.php:208
1281
+ #: adminpages/reports/sales.php:217
1282
+ msgid "All Levels"
1283
+ msgstr ""
1284
+
1285
+ #: adminpages/memberslist.php:42
1286
+ msgid "Cancelled Members"
1287
+ msgstr ""
1288
+
1289
+ #: adminpages/memberslist.php:43
1290
+ msgid "Expired Members"
1291
+ msgstr ""
1292
+
1293
+ #: adminpages/memberslist.php:44 adminpages/memberslist.php:42
1294
+ msgid "Old Members"
1295
+ msgstr ""
1296
+
1297
+ #: adminpages/memberslist.php:49 adminpages/memberslist.php:52
1298
+ #: adminpages/memberslist.php:46 adminpages/memberslist.php:47
1299
+ #: adminpages/memberslist.php:50
1300
+ msgid "Search Members"
1301
+ msgstr ""
1302
+
1303
+ #: adminpages/memberslist.php:156 adminpages/memberslist.php:103
1304
+ #: adminpages/memberslist.php:136 adminpages/memberslist.php:146
1305
+ #, php-format
1306
+ msgid "%d members found."
1307
+ msgstr ""
1308
+
1309
+ #: adminpages/memberslist.php:165 pages/checkout.php:180
1310
+ #: shortcodes/pmpro_account.php:105 adminpages/memberslist.php:112
1311
+ #: adminpages/memberslist.php:145 adminpages/memberslist.php:155 pages/account.php:51
1312
+ #: pages/account.php:55 pages/account.php:76 pages/checkout.php:168
1313
+ #: pages/checkout.php:171 pages/checkout.php:173
1314
+ msgid "Username"
1315
+ msgstr ""
1316
+
1317
+ #: adminpages/memberslist.php:166 adminpages/memberslist.php:113
1318
+ #: adminpages/memberslist.php:146 adminpages/memberslist.php:156
1319
+ msgid "First&nbsp;Name"
1320
+ msgstr ""
1321
+
1322
+ #: adminpages/memberslist.php:167 adminpages/memberslist.php:114
1323
+ #: adminpages/memberslist.php:147 adminpages/memberslist.php:157
1324
+ msgid "Last&nbsp;Name"
1325
+ msgstr ""
1326
+
1327
+ #: adminpages/memberslist.php:170 pages/billing.php:71 pages/checkout.php:311
1328
+ #: pages/confirmation.php:61 pages/invoice.php:48 adminpages/memberslist.php:117
1329
+ #: adminpages/memberslist.php:150 adminpages/memberslist.php:160 pages/account.php:90
1330
+ #: pages/account.php:94 pages/billing.php:58 pages/billing.php:62 pages/checkout.php:298
1331
+ #: pages/checkout.php:300 pages/checkout.php:302 pages/checkout.php:314
1332
+ #: pages/checkout.php:321 pages/confirmation.php:59 pages/invoice.php:46
1333
+ msgid "Billing Address"
1334
+ msgstr ""
1335
+
1336
+ #: adminpages/memberslist.php:171 adminpages/reports/login.php:145
1337
+ #: classes/gateways/class.pmprogateway_authorizenet.php:303
1338
+ #: adminpages/memberslist.php:118 adminpages/memberslist.php:151
1339
+ #: adminpages/memberslist.php:161 adminpages/pagesettings.php:51
1340
+ #: adminpages/reports/login.php:143
1341
+ #: classes/gateways/class.pmprogateway_authorizenet.php:187
1342
+ msgid "Membership"
1343
+ msgstr ""
1344
+
1345
+ #: adminpages/memberslist.php:172 adminpages/memberslist.php:119
1346
+ #: adminpages/memberslist.php:152 adminpages/memberslist.php:162
1347
+ msgid "Fee"
1348
+ msgstr ""
1349
+
1350
+ #: adminpages/memberslist.php:173 adminpages/reports/login.php:146
1351
+ #: adminpages/memberslist.php:120 adminpages/memberslist.php:153
1352
+ #: adminpages/memberslist.php:163 adminpages/reports/login.php:144
1353
+ msgid "Joined"
1354
+ msgstr ""
1355
+
1356
+ #: adminpages/memberslist.php:177 adminpages/memberslist.php:157
1357
+ #: adminpages/memberslist.php:167
1358
+ msgid "Ended"
1359
+ msgstr ""
1360
+
1361
+ #: adminpages/memberslist.php:261 adminpages/reports/login.php:212
1362
+ #: adminpages/memberslist.php:195 adminpages/memberslist.php:223
1363
+ #: adminpages/memberslist.php:251 adminpages/reports/login.php:210
1364
+ msgid "No members found."
1365
+ msgstr ""
1366
+
1367
+ #: adminpages/memberslist.php:261 adminpages/reports/login.php:212
1368
+ #: adminpages/memberslist.php:195 adminpages/memberslist.php:223
1369
+ #: adminpages/memberslist.php:251 adminpages/reports/login.php:210
1370
+ msgid "Search all levels"
1371
+ msgstr ""
1372
+
1373
+ #: adminpages/orders.php:67 adminpages/orders.php:26
1374
+ msgid "Order deleted successfully."
1375
+ msgstr ""
1376
+
1377
+ #: adminpages/orders.php:72 adminpages/orders.php:31
1378
+ msgid "Error deleting order."
1379
+ msgstr ""
1380
+
1381
+ #: adminpages/orders.php:169 adminpages/orders.php:119
1382
+ msgid "Order saved successfully."
1383
+ msgstr ""
1384
+
1385
+ #: adminpages/orders.php:174 adminpages/orders.php:124
1386
+ msgid "Error updating order timestamp."
1387
+ msgstr ""
1388
+
1389
+ #: adminpages/orders.php:180 adminpages/orders.php:130
1390
+ msgid "Error saving order."
1391
+ msgstr ""
1392
+
1393
+ #: adminpages/orders.php:245 adminpages/orders.php:195
1394
+ msgid "Order"
1395
+ msgstr ""
1396
+
1397
+ #: adminpages/orders.php:247 adminpages/orders.php:197
1398
+ msgid "New Order"
1399
+ msgstr ""
1400
+
1401
+ #: adminpages/orders.php:270 adminpages/orders.php:220
1402
+ msgid "Randomly generated for you."
1403
+ msgstr ""
1404
+
1405
+ #: adminpages/orders.php:275 adminpages/orders.php:225
1406
+ msgid "User ID"
1407
+ msgstr ""
1408
+
1409
+ #: adminpages/orders.php:284 adminpages/orders.php:234
1410
+ msgid "Membership Level ID"
1411
+ msgstr ""
1412
+
1413
+ #: adminpages/orders.php:293 adminpages/orders.php:243
1414
+ msgid "Billing Name"
1415
+ msgstr ""
1416
+
1417
+ #: adminpages/orders.php:301 adminpages/orders.php:251
1418
+ msgid "Billing Street"
1419
+ msgstr ""
1420
+
1421
+ #: adminpages/orders.php:308 adminpages/orders.php:258
1422
+ msgid "Billing City"
1423
+ msgstr ""
1424
+
1425
+ #: adminpages/orders.php:315 adminpages/orders.php:265
1426
+ msgid "Billing State"
1427
+ msgstr ""
1428
+
1429
+ #: adminpages/orders.php:322 adminpages/orders.php:272
1430
+ msgid "Billing Postal Code"
1431
+ msgstr ""
1432
+
1433
+ #: adminpages/orders.php:329 adminpages/orders.php:279
1434
+ msgid "Billing Country"
1435
+ msgstr ""
1436
+
1437
+ #: adminpages/orders.php:337 adminpages/orders.php:287
1438
+ msgid "Billing Phone"
1439
+ msgstr ""
1440
+
1441
+ #: adminpages/orders.php:346 adminpages/orders.php:296
1442
+ msgid "Sub Total"
1443
+ msgstr ""
1444
+
1445
+ #: adminpages/orders.php:354 pages/invoice.php:80 adminpages/orders.php:304
1446
+ #: pages/invoice.php:78
1447
+ msgid "Tax"
1448
+ msgstr ""
1449
+
1450
+ #: adminpages/orders.php:362 adminpages/orders.php:312
1451
+ msgid "Coupon Amount"
1452
+ msgstr ""
1453
+
1454
+ #: adminpages/orders.php:370 adminpages/orders.php:915 pages/invoice.php:84
1455
+ #: adminpages/orders.php:320 adminpages/orders.php:602 adminpages/orders.php:905
1456
+ #: pages/invoice.php:82
1457
+ msgid "Total"
1458
+ msgstr ""
1459
+
1460
+ #: adminpages/orders.php:375 adminpages/orders.php:325
1461
+ msgid "Should be subtotal + tax - couponamount."
1462
+ msgstr ""
1463
+
1464
+ #: adminpages/orders.php:380 adminpages/orders.php:330
1465
+ msgid "Payment Type"
1466
+ msgstr ""
1467
+
1468
+ #: adminpages/orders.php:385 adminpages/orders.php:335
1469
+ msgid "e.g. PayPal Express, PayPal Standard, Credit Card."
1470
+ msgstr ""
1471
+
1472
+ #: adminpages/orders.php:389 classes/gateways/class.pmprogateway_braintree.php:304
1473
+ #: classes/gateways/class.pmprogateway_stripe.php:409 pages/billing.php:247
1474
+ #: pages/checkout.php:516 adminpages/orders.php:339
1475
+ #: classes/gateways/class.pmprogateway_braintree.php:291
1476
+ #: classes/gateways/class.pmprogateway_stripe.php:408 pages/billing.php:234
1477
+ #: pages/billing.php:238 pages/checkout.php:493 pages/checkout.php:507
1478
+ #: pages/checkout.php:510 pages/checkout.php:517
1479
+ msgid "Card Type"
1480
+ msgstr ""
1481
+
1482
+ #: adminpages/orders.php:394 adminpages/orders.php:344
1483
+ msgid "e.g. Visa, MasterCard, AMEX, etc"
1484
+ msgstr ""
1485
+
1486
+ #: adminpages/orders.php:398 classes/gateways/class.pmprogateway_twocheckout.php:148
1487
+ #: adminpages/orders.php:348 adminpages/paymentsettings.php:347
1488
+ #: adminpages/paymentsettings.php:352
1489
+ #: classes/gateways/class.pmprogateway_twocheckout.php:129
1490
+ msgid "Account Number"
1491
+ msgstr ""
1492
+
1493
+ #: adminpages/orders.php:403 adminpages/orders.php:353
1494
+ msgid "Obscure all but last 4 digits."
1495
+ msgstr ""
1496
+
1497
+ #: adminpages/orders.php:408 adminpages/orders.php:358
1498
+ msgid "Expiration Month"
1499
+ msgstr ""
1500
+
1501
+ #: adminpages/orders.php:415 adminpages/orders.php:365
1502
+ msgid "Expiration Year"
1503
+ msgstr ""
1504
+
1505
+ #: adminpages/orders.php:423 adminpages/orders.php:919 adminpages/orders.php:373
1506
+ #: adminpages/orders.php:606 adminpages/orders.php:909
1507
+ msgid "Status"
1508
+ msgstr ""
1509
+
1510
+ #: adminpages/orders.php:444 adminpages/orders.php:917 adminpages/orders.php:394
1511
+ #: adminpages/orders.php:604 adminpages/orders.php:907
1512
+ msgid "Gateway"
1513
+ msgstr ""
1514
+
1515
+ #: adminpages/orders.php:462 adminpages/paymentsettings.php:124
1516
+ #: adminpages/orders.php:411 adminpages/orders.php:461
1517
+ #: adminpages/paymentsettings.php:175 adminpages/paymentsettings.php:179
1518
+ #: adminpages/paymentsettings.php:184
1519
+ msgid "Gateway Environment"
1520
+ msgstr ""
1521
+
1522
+ #: adminpages/orders.php:466 adminpages/paymentsettings.php:128
1523
+ #: adminpages/orders.php:415 adminpages/orders.php:465
1524
+ #: adminpages/paymentsettings.php:179 adminpages/paymentsettings.php:183
1525
+ #: adminpages/paymentsettings.php:188
1526
+ msgid "Sandbox/Testing"
1527
+ msgstr ""
1528
+
1529
+ #: adminpages/orders.php:467 adminpages/paymentsettings.php:129
1530
+ #: adminpages/orders.php:416 adminpages/orders.php:466
1531
+ #: adminpages/paymentsettings.php:180 adminpages/paymentsettings.php:184
1532
+ #: adminpages/paymentsettings.php:189
1533
+ msgid "Live/Production"
1534
+ msgstr ""
1535
+
1536
+ #: adminpages/orders.php:474 adminpages/orders.php:423 adminpages/orders.php:473
1537
+ msgid "Payment Transaction ID"
1538
+ msgstr ""
1539
+
1540
+ #: adminpages/orders.php:479 adminpages/orders.php:428 adminpages/orders.php:478
1541
+ msgid "Generated by the gateway. Useful to cross reference orders."
1542
+ msgstr ""
1543
+
1544
+ #: adminpages/orders.php:483 adminpages/orders.php:432 adminpages/orders.php:482
1545
+ msgid "Subscription Transaction ID"
1546
+ msgstr ""
1547
+
1548
+ #: adminpages/orders.php:488 adminpages/orders.php:437 adminpages/orders.php:487
1549
+ msgid "Generated by the gateway. Useful to cross reference subscriptions."
1550
+ msgstr ""
1551
+
1552
+ #: adminpages/orders.php:493 adminpages/orders.php:920 pages/invoice.php:107
1553
+ #: shortcodes/pmpro_account.php:122 adminpages/orders.php:442 adminpages/orders.php:492
1554
+ #: adminpages/orders.php:607 adminpages/orders.php:910 pages/account.php:91
1555
+ #: pages/invoice.php:105
1556
+ msgid "Date"
1557
+ msgstr ""
1558
+
1559
+ #: adminpages/orders.php:527 adminpages/orders.php:477
1560
+ msgid "Affiliate ID"
1561
+ msgstr ""
1562
+
1563
+ #: adminpages/orders.php:535 adminpages/orders.php:485
1564
+ msgid "Affiliate SubID"
1565
+ msgstr ""
1566
+
1567
+ #: adminpages/orders.php:545 adminpages/orders.php:495
1568
+ msgid "Notes"
1569
+ msgstr ""
1570
+
1571
+ #: adminpages/orders.php:560 adminpages/orders.php:510
1572
+ msgid "Save Order"
1573
+ msgstr ""
1574
+
1575
+ #: adminpages/orders.php:570 includes/adminpages.php:55 includes/adminpages.php:167
1576
+ #: adminpages/orders.php:520 includes/adminpages.php:17 includes/adminpages.php:84
1577
+ #: includes/adminpages.php:156 includes/adminpages.php:163
1578
+ msgid "Orders"
1579
+ msgstr ""
1580
+
1581
+ #: adminpages/orders.php:571 adminpages/orders.php:521
1582
+ msgid "Add New Order"
1583
+ msgstr ""
1584
+
1585
+ #: adminpages/orders.php:606
1586
+ msgid "Within a Date Range"
1587
+ msgstr ""
1588
+
1589
+ #: adminpages/orders.php:607
1590
+ msgid "Predefined Date Range"
1591
+ msgstr ""
1592
+
1593
+ #: adminpages/orders.php:608
1594
+ msgid "Within a Level"
1595
+ msgstr ""
1596
+
1597
+ #: adminpages/orders.php:609
1598
+ msgid "Within a Status"
1599
+ msgstr ""
1600
+
1601
+ #: adminpages/orders.php:612
1602
+ msgid "From"
1603
+ msgstr ""
1604
+
1605
+ #: adminpages/orders.php:624
1606
+ msgid "To"
1607
+ msgstr ""
1608
+
1609
+ #: adminpages/orders.php:636
1610
+ msgid "filter by "
1611
+ msgstr ""
1612
+
1613
+ #: adminpages/orders.php:674
1614
+ msgid "Filter"
1615
+ msgstr ""
1616
+
1617
+ #: adminpages/orders.php:777 adminpages/orders.php:780 adminpages/orders.php:535
1618
+ #: adminpages/orders.php:538
1619
+ msgid "Search Orders"
1620
+ msgstr ""
1621
+
1622
+ #: adminpages/orders.php:903 adminpages/orders.php:590 adminpages/orders.php:893
1623
+ #, php-format
1624
+ msgid "%d orders found."
1625
+ msgstr ""
1626
+
1627
+ #: adminpages/orders.php:912 adminpages/reports/login.php:143
1628
+ #: classes/gateways/class.pmprogateway_payflowpro.php:116 adminpages/orders.php:599
1629
+ #: adminpages/orders.php:902 adminpages/paymentsettings.php:211
1630
+ #: adminpages/paymentsettings.php:215 adminpages/paymentsettings.php:220
1631
+ #: adminpages/reports/login.php:141
1632
+ msgid "User"
1633
+ msgstr ""
1634
+
1635
+ #: adminpages/orders.php:914 includes/init.php:222 includes/profile.php:27
1636
+ #: pages/checkout.php:42 pages/confirmation.php:47 pages/confirmation.php:64
1637
+ #: pages/confirmation.php:105 pages/invoice.php:28 pages/invoice.php:51
1638
+ #: adminpages/orders.php:601 adminpages/orders.php:904 includes/init.php:214
1639
+ #: includes/init.php:217 includes/init.php:218 includes/init.php:220
1640
+ #: includes/profile.php:25 pages/checkout.php:33 pages/checkout.php:34
1641
+ #: pages/checkout.php:35 pages/confirmation.php:46 pages/confirmation.php:62
1642
+ #: pages/confirmation.php:103 pages/invoice.php:27 pages/invoice.php:49
1643
+ msgid "Membership Level"
1644
+ msgstr ""
1645
+
1646
+ #: adminpages/orders.php:916 adminpages/orders.php:982 adminpages/orders.php:603
1647
+ #: adminpages/orders.php:651 adminpages/orders.php:906 adminpages/orders.php:954
1648
+ #: adminpages/orders.php:972
1649
+ msgid "Payment"
1650
+ msgstr ""
1651
+
1652
+ #: adminpages/orders.php:918 adminpages/orders.php:605 adminpages/orders.php:908
1653
+ msgid "Transaction IDs"
1654
+ msgstr ""
1655
+
1656
+ #: adminpages/orders.php:943 adminpages/orders.php:630 adminpages/orders.php:933
1657
+ msgid "deleted"
1658
+ msgstr ""
1659
+
1660
+ #: adminpages/orders.php:984 adminpages/orders.php:653 adminpages/orders.php:956
1661
+ #: adminpages/orders.php:974
1662
+ msgid "Subscription"
1663
+ msgstr ""
1664
+
1665
+ #: adminpages/orders.php:998 adminpages/orders.php:664 adminpages/orders.php:967
1666
+ #: adminpages/orders.php:985 adminpages/orders.php:995
1667
+ #, php-format
1668
+ msgid ""
1669
+ "Deleting orders is permanent and can affect active users. Are you sure you want to "
1670
+ "delete order %s?"
1671
+ msgstr ""
1672
+
1673
+ #: adminpages/orders.php:1008 adminpages/orders.php:674 adminpages/orders.php:977
1674
+ #: adminpages/orders.php:995 adminpages/orders.php:1005
1675
+ msgid "No orders found."
1676
+ msgstr ""
1677
+
1678
+ #: adminpages/pagesettings.php:51
1679
+ msgid "Membership Account"
1680
+ msgstr ""
1681
+
1682
+ #: adminpages/pagesettings.php:54
1683
+ msgid "Membership Billing"
1684
+ msgstr ""
1685
+
1686
+ #: adminpages/pagesettings.php:57
1687
+ msgid "Membership Cancel"
1688
+ msgstr ""
1689
+
1690
+ #: adminpages/pagesettings.php:60
1691
+ msgid "Membership Checkout"
1692
+ msgstr ""
1693
+
1694
+ #: adminpages/pagesettings.php:63
1695
+ msgid "Membership Confirmation"
1696
+ msgstr ""
1697
+
1698
+ #: adminpages/pagesettings.php:66
1699
+ msgid "Membership Invoice"
1700
+ msgstr ""
1701
+
1702
+ #: adminpages/pagesettings.php:73
1703
+ #, php-format
1704
+ msgid "Membership %s"
1705
+ msgstr ""
1706
+
1707
+ #: adminpages/pagesettings.php:111 adminpages/pagesettings.php:83
1708
+ msgid "The following pages have been created for you"
1709
+ msgstr ""
1710
+
1711
+ #: adminpages/pagesettings.php:126 adminpages/pagesettings.php:98
1712
+ msgid "Manage the WordPress pages assigned to each required Paid Memberships Pro page."
1713
+ msgstr ""
1714
+
1715
+ #: adminpages/pagesettings.php:132 adminpages/pagesettings.php:104
1716
+ msgid "Assign the WordPress pages for each required Paid Memberships Pro page or"
1717
+ msgstr ""
1718
+
1719
+ #: adminpages/pagesettings.php:132 adminpages/pagesettings.php:104
1720
+ msgid "click here to let us generate them for you"
1721
+ msgstr ""
1722
+
1723
+ #: adminpages/pagesettings.php:140 adminpages/pagesettings.php:112
1724
+ msgid "Account Page"
1725
+ msgstr ""
1726
+
1727
+ #: adminpages/pagesettings.php:144 adminpages/pagesettings.php:159
1728
+ #: adminpages/pagesettings.php:174 adminpages/pagesettings.php:190
1729
+ #: adminpages/pagesettings.php:206 adminpages/pagesettings.php:222
1730
+ #: adminpages/pagesettings.php:238 adminpages/pagesettings.php:147
1731
+ #: adminpages/pagesettings.php:162 adminpages/pagesettings.php:177
1732
+ #: adminpages/pagesettings.php:193 adminpages/pagesettings.php:209
1733
+ #: adminpages/pagesettings.php:225 adminpages/pagesettings.php:241
1734
+ msgid "Choose One"
1735
+ msgstr ""
1736
+
1737
+ #: adminpages/pagesettings.php:147 adminpages/pagesettings.php:162
1738
+ #: adminpages/pagesettings.php:177 adminpages/pagesettings.php:193
1739
+ #: adminpages/pagesettings.php:209 adminpages/pagesettings.php:225
1740
+ #: adminpages/pagesettings.php:241 adminpages/pagesettings.php:119
1741
+ #: adminpages/pagesettings.php:132 adminpages/pagesettings.php:134
1742
+ #: adminpages/pagesettings.php:145 adminpages/pagesettings.php:149
1743
+ #: adminpages/pagesettings.php:150 adminpages/pagesettings.php:159
1744
+ #: adminpages/pagesettings.php:165 adminpages/pagesettings.php:173
1745
+ #: adminpages/pagesettings.php:180 adminpages/pagesettings.php:181
1746
+ #: adminpages/pagesettings.php:187 adminpages/pagesettings.php:196
1747
+ #: adminpages/pagesettings.php:197 adminpages/pagesettings.php:201
1748
+ #: adminpages/pagesettings.php:212 adminpages/pagesettings.php:213
1749
+ #: adminpages/pagesettings.php:228 adminpages/pagesettings.php:244
1750
+ msgid "edit page"
1751
+ msgstr ""
1752
+
1753
+ #: adminpages/pagesettings.php:149 adminpages/pagesettings.php:164
1754
+ #: adminpages/pagesettings.php:179 adminpages/pagesettings.php:195
1755
+ #: adminpages/pagesettings.php:211 adminpages/pagesettings.php:227
1756
+ #: adminpages/pagesettings.php:243 adminpages/pagesettings.php:121
1757
+ #: adminpages/pagesettings.php:136 adminpages/pagesettings.php:151
1758
+ #: adminpages/pagesettings.php:152 adminpages/pagesettings.php:167
1759
+ #: adminpages/pagesettings.php:182 adminpages/pagesettings.php:183
1760
+ #: adminpages/pagesettings.php:198 adminpages/pagesettings.php:199
1761
+ #: adminpages/pagesettings.php:214 adminpages/pagesettings.php:215
1762
+ #: adminpages/pagesettings.php:230 adminpages/pagesettings.php:246
1763
+ msgid "view page"
1764
+ msgstr ""
1765
+
1766
+ #: adminpages/pagesettings.php:151 adminpages/pagesettings.php:166
1767
+ #: adminpages/pagesettings.php:181 adminpages/pagesettings.php:197
1768
+ #: adminpages/pagesettings.php:213 adminpages/pagesettings.php:229
1769
+ #: adminpages/pagesettings.php:245 adminpages/pagesettings.php:121
1770
+ #: adminpages/pagesettings.php:123 adminpages/pagesettings.php:134
1771
+ #: adminpages/pagesettings.php:138 adminpages/pagesettings.php:147
1772
+ #: adminpages/pagesettings.php:153 adminpages/pagesettings.php:154
1773
+ #: adminpages/pagesettings.php:161 adminpages/pagesettings.php:169
1774
+ #: adminpages/pagesettings.php:175 adminpages/pagesettings.php:184
1775
+ #: adminpages/pagesettings.php:185 adminpages/pagesettings.php:189
1776
+ #: adminpages/pagesettings.php:200 adminpages/pagesettings.php:201
1777
+ #: adminpages/pagesettings.php:203 adminpages/pagesettings.php:216
1778
+ #: adminpages/pagesettings.php:217 adminpages/pagesettings.php:232
1779
+ #: adminpages/pagesettings.php:248
1780
+ msgid "Include the shortcode"
1781
+ msgstr ""
1782
+
1783
+ #: adminpages/pagesettings.php:155 adminpages/pagesettings.php:125
1784
+ #: adminpages/pagesettings.php:127 adminpages/pagesettings.php:158
1785
+ msgid "Billing Information Page"
1786
+ msgstr ""
1787
+
1788
+ #: adminpages/pagesettings.php:170 adminpages/pagesettings.php:138
1789
+ #: adminpages/pagesettings.php:142 adminpages/pagesettings.php:173
1790
+ msgid "Cancel Page"
1791
+ msgstr ""
1792
+
1793
+ #: adminpages/pagesettings.php:186 adminpages/pagesettings.php:152
1794
+ #: adminpages/pagesettings.php:158 adminpages/pagesettings.php:189
1795
+ msgid "Checkout Page"
1796
+ msgstr ""
1797
+
1798
+ #: adminpages/pagesettings.php:202 adminpages/pagesettings.php:166
1799
+ #: adminpages/pagesettings.php:174 adminpages/pagesettings.php:205
1800
+ msgid "Confirmation Page"
1801
+ msgstr ""
1802
+
1803
+ #: adminpages/pagesettings.php:218 adminpages/pagesettings.php:180
1804
+ #: adminpages/pagesettings.php:190 adminpages/pagesettings.php:221
1805
+ msgid "Invoice Page"
1806
+ msgstr ""
1807
+
1808
+ #: adminpages/pagesettings.php:234 adminpages/pagesettings.php:194
1809
+ #: adminpages/pagesettings.php:206 adminpages/pagesettings.php:237
1810
+ msgid "Levels Page"
1811
+ msgstr ""
1812
+
1813
+ #: adminpages/paymentsettings.php:49 adminpages/paymentsettings.php:77
1814
+ #: adminpages/paymentsettings.php:82
1815
+ msgid "Your payment settings have been updated."
1816
+ msgstr ""
1817
+
1818
+ #: adminpages/paymentsettings.php:93 adminpages/paymentsettings.php:106
1819
+ #: adminpages/paymentsettings.php:144 adminpages/paymentsettings.php:146
1820
+ #: adminpages/paymentsettings.php:152 adminpages/paymentsettings.php:154
1821
+ msgid "Payment Gateway"
1822
+ msgstr ""
1823
+
1824
+ #: adminpages/paymentsettings.php:93 adminpages/paymentsettings.php:144
1825
+ #: adminpages/paymentsettings.php:146
1826
+ msgid "SSL Settings"
1827
+ msgstr ""
1828
+
1829
+ #: adminpages/paymentsettings.php:95 adminpages/paymentsettings.php:148
1830
+ msgid ""
1831
+ "Learn more about <a title=\"Paid Memberships Pro - SSL Settings\" target=\"_blank\" "
1832
+ "href=\"http://www.paidmembershipspro.com/support/initial-plugin-setup/ssl/\">SSL</a> "
1833
+ "or <a title=\"Paid Memberships Pro - Payment Gateway Settings\" target=\"_blank\" "
1834
+ "href=\"http://www.paidmembershipspro.com/support/initial-plugin-setup/payment-gateway/"
1835
+ "\">Payment Gateway Settings</a>."
1836
+ msgstr ""
1837
+
1838
+ #: adminpages/paymentsettings.php:153 adminpages/paymentsettings.php:327
1839
+ #: adminpages/paymentsettings.php:337 adminpages/paymentsettings.php:356
1840
+ #: adminpages/paymentsettings.php:381 adminpages/paymentsettings.php:386
1841
+ msgid "Currency"
1842
+ msgstr ""
1843
+
1844
+ #: adminpages/paymentsettings.php:169 adminpages/paymentsettings.php:400
1845
+ #: adminpages/paymentsettings.php:402
1846
+ msgid ""
1847
+ "Not all currencies will be supported by every gateway. Please check with your gateway."
1848
+ msgstr ""
1849
+
1850
+ #: adminpages/paymentsettings.php:174 adminpages/paymentsettings.php:375
1851
+ #: adminpages/paymentsettings.php:401 adminpages/paymentsettings.php:406
1852
+ #: adminpages/paymentsettings.php:408
1853
+ msgid "Accepted Credit Card Types"
1854
+ msgstr ""
1855
+
1856
+ #: adminpages/paymentsettings.php:188 adminpages/paymentsettings.php:398
1857
+ #: adminpages/paymentsettings.php:438 adminpages/paymentsettings.php:443
1858
+ #: adminpages/paymentsettings.php:445
1859
+ msgid "Sales Tax"
1860
+ msgstr ""
1861
+
1862
+ #: adminpages/paymentsettings.php:188 pages/billing.php:91
1863
+ #: adminpages/paymentsettings.php:398 adminpages/paymentsettings.php:438
1864
+ #: adminpages/paymentsettings.php:443 adminpages/paymentsettings.php:445
1865
+ #: pages/billing.php:78 pages/billing.php:82
1866
+ msgid "optional"
1867
+ msgstr ""
1868
+
1869
+ #: adminpages/paymentsettings.php:191 adminpages/paymentsettings.php:401
1870
+ #: adminpages/paymentsettings.php:441 adminpages/paymentsettings.php:446
1871
+ #: adminpages/paymentsettings.php:448
1872
+ msgid "Tax State"
1873
+ msgstr ""
1874
+
1875
+ #: adminpages/paymentsettings.php:192 adminpages/paymentsettings.php:402
1876
+ #: adminpages/paymentsettings.php:442 adminpages/paymentsettings.php:447
1877
+ #: adminpages/paymentsettings.php:449
1878
+ msgid "abbreviation, e.g. \"PA\""
1879
+ msgstr ""
1880
+
1881
+ #: adminpages/paymentsettings.php:194 adminpages/paymentsettings.php:404
1882
+ #: adminpages/paymentsettings.php:444 adminpages/paymentsettings.php:449
1883
+ #: adminpages/paymentsettings.php:451
1884
+ msgid "decimal, e.g. \"0.06\""
1885
+ msgstr ""
1886
+
1887
+ #: adminpages/paymentsettings.php:195 adminpages/paymentsettings.php:450
1888
+ #: adminpages/paymentsettings.php:452
1889
+ msgid ""
1890
+ "US only. If values are given, tax will be applied for any members ordering from the "
1891
+ "selected state.<br />For non-US or more complex tax rules, use the <a target=\"_blank"
1892
+ "\" href=\"http://www.paidmembershipspro.com/2013/10/non-us-taxes-paid-memberships-pro/"
1893
+ "\">pmpro_tax filter</a>."
1894
+ msgstr ""
1895
+
1896
+ #: adminpages/paymentsettings.php:206 adminpages/paymentsettings.php:450
1897
+ #: adminpages/paymentsettings.php:455 adminpages/paymentsettings.php:457
1898
+ msgid "Force SSL"
1899
+ msgstr ""
1900
+
1901
+ #: adminpages/paymentsettings.php:212 adminpages/paymentsettings.php:456
1902
+ #: adminpages/paymentsettings.php:461 adminpages/paymentsettings.php:463
1903
+ msgid "Yes (with JavaScript redirects)"
1904
+ msgstr ""
1905
+
1906
+ #: adminpages/paymentsettings.php:219 adminpages/paymentsettings.php:430
1907
+ #: adminpages/paymentsettings.php:463 adminpages/paymentsettings.php:468
1908
+ #: adminpages/paymentsettings.php:470
1909
+ msgid "SSL Seal Code"
1910
+ msgstr ""
1911
+
1912
+ #: adminpages/paymentsettings.php:228
1913
+ msgid "Extra HTTPS URL Filter"
1914
+ msgstr ""
1915
+
1916
+ #: adminpages/paymentsettings.php:231
1917
+ msgid ""
1918
+ "Pass all generated HTML through a URL filter to add HTTPS to URLs used on secure "
1919
+ "pages. Check this if you are using SSL and have warnings on your checkout pages."
1920
+ msgstr ""
1921
+
1922
+ #: adminpages/reports.php:40 adminpages/reports.php:26 adminpages/reports.php:37
1923
+ msgid "Details"
1924
+ msgstr ""
1925
+
1926
+ #: adminpages/reports/login.php:16
1927
+ msgid "Visits, Views, and Logins"
1928
+ msgstr ""
1929
+
1930
+ #: adminpages/reports/login.php:27 adminpages/reports/login.php:26
1931
+ msgid "Visits Today"
1932
+ msgstr ""
1933
+
1934
+ #: adminpages/reports/login.php:28 adminpages/reports/login.php:149
1935
+ #: adminpages/reports/login.php:27 adminpages/reports/login.php:147
1936
+ msgid "Visits This Month"
1937
+ msgstr ""
1938
+
1939
+ #: adminpages/reports/login.php:29 adminpages/reports/login.php:28
1940
+ msgid "Visits All Time"
1941
+ msgstr ""
1942
+
1943
+ #: adminpages/reports/login.php:32 adminpages/reports/login.php:31
1944
+ msgid "Views Today"
1945
+ msgstr ""
1946
+
1947
+ #: adminpages/reports/login.php:33 adminpages/reports/login.php:151
1948
+ #: adminpages/reports/login.php:32 adminpages/reports/login.php:149
1949
+ msgid "Views This Month"
1950
+ msgstr ""
1951
+
1952
+ #: adminpages/reports/login.php:34 adminpages/reports/login.php:33
1953
+ msgid "Views All Time"
1954
+ msgstr ""
1955
+
1956
+ #: adminpages/reports/login.php:37 adminpages/reports/login.php:36
1957
+ msgid "Logins Today"
1958
+ msgstr ""
1959
+
1960
+ #: adminpages/reports/login.php:38 adminpages/reports/login.php:154
1961
+ #: adminpages/reports/login.php:37 adminpages/reports/login.php:152
1962
+ msgid "Logins This Month"
1963
+ msgstr ""
1964
+
1965
+ #: adminpages/reports/login.php:39 adminpages/reports/login.php:38
1966
+ msgid "Logins All Time"
1967
+ msgstr ""
1968
+
1969
+ #: adminpages/reports/login.php:63 adminpages/reports/login.php:61
1970
+ msgid "Visits, Views, and Logins Report"
1971
+ msgstr ""
1972
+
1973
+ #: adminpages/reports/login.php:68 adminpages/reports/login.php:66
1974
+ msgid "All Users"
1975
+ msgstr ""
1976
+
1977
+ #: adminpages/reports/login.php:148 adminpages/reports/login.php:146
1978
+ msgid "Last Visit"
1979
+ msgstr ""
1980
+
1981
+ #: adminpages/reports/login.php:150 adminpages/reports/login.php:148
1982
+ msgid "Total Visits"
1983
+ msgstr ""
1984
+
1985
+ #: adminpages/reports/login.php:152 adminpages/reports/login.php:150
1986
+ msgid "Total Views"
1987
+ msgstr ""
1988
+
1989
+ #: adminpages/reports/login.php:153 adminpages/reports/login.php:151
1990
+ msgid "Last Login"
1991
+ msgstr ""
1992
+
1993
+ #: adminpages/reports/login.php:155 adminpages/reports/login.php:153
1994
+ msgid "Total Logins"
1995
+ msgstr ""
1996
+
1997
+ #: adminpages/reports/memberships.php:18 adminpages/reports/memberships.php:288
1998
+ msgid "Membership Stats"
1999
+ msgstr ""
2000
+
2001
+ #: adminpages/reports/memberships.php:48
2002
+ msgid "Signups"
2003
+ msgstr ""
2004
+
2005
+ #: adminpages/reports/memberships.php:50 adminpages/reports/memberships.php:69
2006
+ msgid "All Time"
2007
+ msgstr ""
2008
+
2009
+ #: adminpages/reports/memberships.php:54 adminpages/reports/memberships.php:73
2010
+ msgid "This Year"
2011
+ msgstr ""
2012
+
2013
+ #: adminpages/reports/memberships.php:58 adminpages/reports/memberships.php:77
2014
+ msgid "This Month"
2015
+ msgstr ""
2016
+
2017
+ #: adminpages/reports/memberships.php:62 adminpages/reports/memberships.php:81
2018
+ msgid "Today"
2019
+ msgstr ""
2020
+
2021
+ #: adminpages/reports/memberships.php:67
2022
+ msgid "Cancellations"
2023
+ msgstr ""
2024
+
2025
+ #: adminpages/reports/memberships.php:86
2026
+ msgid "Other Stats"
2027
+ msgstr ""
2028
+
2029
+ #: adminpages/reports/memberships.php:88
2030
+ msgid "Monthly Recurring Revenue (MRR)"
2031
+ msgstr ""
2032
+
2033
+ #: adminpages/reports/memberships.php:92
2034
+ msgid "Cancellation Rate"
2035
+ msgstr ""
2036
+
2037
+ #: adminpages/reports/memberships.php:96
2038
+ msgid "Lifetime Value (LTV)"
2039
+ msgstr ""
2040
+
2041
+ #: adminpages/reports/memberships.php:294 adminpages/reports/sales.php:195
2042
+ #: adminpages/reports/sales.php:187 adminpages/reports/sales.php:196
2043
+ msgid "Daily"
2044
+ msgstr ""
2045
+
2046
+ #: adminpages/reports/memberships.php:295 adminpages/reports/sales.php:196
2047
+ #: adminpages/reports/sales.php:188 adminpages/reports/sales.php:197
2048
+ msgid "Monthly"
2049
+ msgstr ""
2050
+
2051
+ #: adminpages/reports/memberships.php:296 adminpages/reports/sales.php:197
2052
+ #: adminpages/reports/sales.php:189 adminpages/reports/sales.php:198
2053
+ msgid "Annual"
2054
+ msgstr ""
2055
+
2056
+ #: adminpages/reports/memberships.php:299
2057
+ msgid "Signups vs. Cancellations"
2058
+ msgstr ""
2059
+
2060
+ #: adminpages/reports/memberships.php:304 adminpages/reports/memberships.php:315
2061
+ #: adminpages/reports/sales.php:203 adminpages/reports/sales.php:214
2062
+ #: adminpages/membershiplevels.php:545 adminpages/membershiplevels.php:551
2063
+ #: adminpages/membershiplevels.php:553 adminpages/membershiplevels.php:559
2064
+ #: adminpages/membershiplevels.php:561 adminpages/membershiplevels.php:580
2065
+ #: adminpages/membershiplevels.php:588 adminpages/reports/sales.php:195
2066
+ #: adminpages/reports/sales.php:204 adminpages/reports/sales.php:206
2067
+ #: adminpages/reports/sales.php:215
2068
+ msgid "for"
2069
+ msgstr ""
2070
+
2071
+ #: adminpages/reports/memberships.php:331 adminpages/reports/sales.php:230
2072
+ #: adminpages/reports/sales.php:222 adminpages/reports/sales.php:231
2073
+ msgid "Generate Report"
2074
+ msgstr ""
2075
+
2076
+ #: adminpages/reports/sales.php:18
2077
+ msgid "Sales and Revenue (Testing/Sandbox)"
2078
+ msgstr ""
2079
+
2080
+ #: adminpages/reports/sales.php:20 adminpages/reports/sales.php:189
2081
+ #: adminpages/reports/sales.php:180
2082
+ msgid "Sales and Revenue"
2083
+ msgstr ""
2084
+
2085
+ #: adminpages/reports/sales.php:200 adminpages/reports/sales.php:192
2086
+ #: adminpages/reports/sales.php:201
2087
+ msgid "Revenue"
2088
+ msgstr ""
2089
+
2090
+ #: adminpages/reports/sales.php:201 adminpages/reports/sales.php:193
2091
+ #: adminpages/reports/sales.php:202
2092
+ msgid "Sales"
2093
+ msgstr ""
2094
+
2095
+ #: classes/class.memberorder.php:644 classes/class.memberorder.php:553
2096
+ #: classes/class.memberorder.php:561 classes/class.memberorder.php:564
2097
+ #: classes/class.memberorder.php:573 includes/cleanup.php:24
2098
+ #, php-format
2099
+ msgid ""
2100
+ "There was an error canceling the subscription for user with ID=%s. You will want to "
2101
+ "check your payment gateway to see if their subscription is still active."
2102
+ msgstr ""
2103
+
2104
+ #: classes/class.pmproemail.php:37
2105
+ #, php-format
2106
+ msgid "An Email From %s"
2107
+ msgstr ""
2108
+
2109
+ #: classes/class.pmproemail.php:134 classes/class.pmproemail.php:120
2110
+ #: classes/class.pmproemail.php:122 classes/class.pmproemail.php:125
2111
+ #, php-format
2112
+ msgid "Your membership at %s has been CANCELLED"
2113
+ msgstr ""
2114
+
2115
+ #: classes/class.pmproemail.php:156 classes/class.pmproemail.php:142
2116
+ #: classes/class.pmproemail.php:144 classes/class.pmproemail.php:147
2117
+ #, php-format
2118
+ msgid "Membership for %s at %s has been CANCELLED"
2119
+ msgstr ""
2120
+
2121
+ #: classes/class.pmproemail.php:187 classes/class.pmproemail.php:172
2122
+ #: classes/class.pmproemail.php:173 classes/class.pmproemail.php:175
2123
+ #: classes/class.pmproemail.php:178
2124
+ #, php-format
2125
+ msgid "Your membership confirmation for %s"
2126
+ msgstr ""
2127
+
2128
+ #: classes/class.pmproemail.php:240 classes/class.pmproemail.php:249
2129
+ #: classes/class.pmproemail.php:258 classes/class.pmproemail.php:337
2130
+ #: classes/class.pmproemail.php:346 classes/class.pmproemail.php:657
2131
+ #: classes/gateways/class.pmprogateway_braintree.php:362
2132
+ #: classes/gateways/class.pmprogateway_stripe.php:496 pages/checkout.php:75
2133
+ #: pages/checkout.php:85 pages/checkout.php:603 pages/confirmation.php:52
2134
+ #: pages/invoice.php:33 classes/class.pmproemail.php:216
2135
+ #: classes/class.pmproemail.php:218 classes/class.pmproemail.php:225
2136
+ #: classes/class.pmproemail.php:227 classes/class.pmproemail.php:228
2137
+ #: classes/class.pmproemail.php:231 classes/class.pmproemail.php:234
2138
+ #: classes/class.pmproemail.php:236 classes/class.pmproemail.php:237
2139
+ #: classes/class.pmproemail.php:246 classes/class.pmproemail.php:304
2140
+ #: classes/class.pmproemail.php:307 classes/class.pmproemail.php:313
2141
+ #: classes/class.pmproemail.php:316 classes/class.pmproemail.php:325
2142
+ #: classes/class.pmproemail.php:328 classes/class.pmproemail.php:334
2143
+ #: classes/class.pmproemail.php:532 classes/class.pmproemail.php:580
2144
+ #: classes/class.pmproemail.php:645 classes/class.pmproemail.php:648
2145
+ #: classes/gateways/class.pmprogateway_braintree.php:349
2146
+ #: classes/gateways/class.pmprogateway_stripe.php:495 pages/checkout.php:66
2147
+ #: pages/checkout.php:67 pages/checkout.php:68 pages/checkout.php:76
2148
+ #: pages/checkout.php:77 pages/checkout.php:78 pages/checkout.php:549
2149
+ #: pages/checkout.php:565 pages/checkout.php:566 pages/checkout.php:573
2150
+ #: pages/checkout.php:594 pages/confirmation.php:51 pages/invoice.php:32
2151
+ msgid "Discount Code"
2152
+ msgstr ""
2153
+
2154
+ #: classes/class.pmproemail.php:265 classes/class.pmproemail.php:358
2155
+ #: classes/class.pmproemail.php:663 classes/class.pmproemail.php:241
2156
+ #: classes/class.pmproemail.php:243 classes/class.pmproemail.php:253
2157
+ #: classes/class.pmproemail.php:256 classes/class.pmproemail.php:325
2158
+ #: classes/class.pmproemail.php:328 classes/class.pmproemail.php:346
2159
+ #: classes/class.pmproemail.php:349 classes/class.pmproemail.php:538
2160
+ #: classes/class.pmproemail.php:586 classes/class.pmproemail.php:651
2161
+ #: classes/class.pmproemail.php:654
2162
+ #, php-format
2163
+ msgid "This membership will expire on %s."
2164
+ msgstr ""
2165
+
2166
+ #: classes/class.pmproemail.php:287 classes/class.pmproemail.php:263
2167
+ #: classes/class.pmproemail.php:265 classes/class.pmproemail.php:275
2168
+ #: classes/class.pmproemail.php:278
2169
+ #, php-format
2170
+ msgid "Member Checkout for %s at %s"
2171
+ msgstr ""
2172
+
2173
+ #: classes/class.pmproemail.php:375 classes/class.pmproemail.php:342
2174
+ #: classes/class.pmproemail.php:345 classes/class.pmproemail.php:363
2175
+ #: classes/class.pmproemail.php:366
2176
+ #, php-format
2177
+ msgid "Your billing information has been udpated at %s"
2178
+ msgstr ""
2179
+
2180
+ #: classes/class.pmproemail.php:428 classes/class.pmproemail.php:386
2181
+ #: classes/class.pmproemail.php:390 classes/class.pmproemail.php:416
2182
+ #: classes/class.pmproemail.php:419
2183
+ #, php-format
2184
+ msgid "Billing information has been udpated for %s at %s"
2185
+ msgstr ""
2186
+
2187
+ #: classes/class.pmproemail.php:476 classes/class.pmproemail.php:425
2188
+ #: classes/class.pmproemail.php:430 classes/class.pmproemail.php:464
2189
+ #: classes/class.pmproemail.php:467
2190
+ #, php-format
2191
+ msgid "Membership Payment Failed at %s"
2192
+ msgstr ""
2193
+
2194
+ #: classes/class.pmproemail.php:522 classes/class.pmproemail.php:462
2195
+ #: classes/class.pmproemail.php:468 classes/class.pmproemail.php:510
2196
+ #: classes/class.pmproemail.php:513
2197
+ #, php-format
2198
+ msgid "Membership Payment Failed For %s at %s"
2199
+ msgstr ""
2200
+
2201
+ #: classes/class.pmproemail.php:569 classes/class.pmproemail.php:508
2202
+ #: classes/class.pmproemail.php:557 classes/class.pmproemail.php:560
2203
+ #, php-format
2204
+ msgid "Credit Card on File Expiring Soon at %s"
2205
+ msgstr ""
2206
+
2207
+ #: classes/class.pmproemail.php:617 classes/class.pmproemail.php:501
2208
+ #: classes/class.pmproemail.php:548 classes/class.pmproemail.php:605
2209
+ #: classes/class.pmproemail.php:608
2210
+ #, php-format
2211
+ msgid "INVOICE for %s membership"
2212
+ msgstr ""
2213
+
2214
+ #: classes/class.pmproemail.php:688 classes/class.pmproemail.php:563
2215
+ #: classes/class.pmproemail.php:611 classes/class.pmproemail.php:676
2216
+ #: classes/class.pmproemail.php:679
2217
+ #, php-format
2218
+ msgid "Your trial at %s is ending soon"
2219
+ msgstr ""
2220
+
2221
+ #: classes/class.pmproemail.php:722 classes/class.pmproemail.php:596
2222
+ #: classes/class.pmproemail.php:645 classes/class.pmproemail.php:710
2223
+ #: classes/class.pmproemail.php:713
2224
+ #, php-format
2225
+ msgid "Your membership at %s has ended"
2226
+ msgstr ""
2227
+
2228
+ #: classes/class.pmproemail.php:747 classes/class.pmproemail.php:621
2229
+ #: classes/class.pmproemail.php:670 classes/class.pmproemail.php:735
2230
+ #: classes/class.pmproemail.php:738
2231
+ #, php-format
2232
+ msgid "Your membership at %s will end soon"
2233
+ msgstr ""
2234
+
2235
+ #: classes/class.pmproemail.php:767 classes/class.pmproemail.php:641
2236
+ #: classes/class.pmproemail.php:690 classes/class.pmproemail.php:755
2237
+ #: classes/class.pmproemail.php:758
2238
+ #, php-format
2239
+ msgid "Your membership at %s has been changed"
2240
+ msgstr ""
2241
+
2242
+ #: classes/class.pmproemail.php:771 classes/class.pmproemail.php:809
2243
+ #: classes/class.pmproemail.php:759 classes/class.pmproemail.php:762
2244
+ #: classes/class.pmproemail.php:800
2245
+ #, php-format
2246
+ msgid "The new level is %s"
2247
+ msgstr ""
2248
+
2249
+ #: classes/class.pmproemail.php:773 classes/class.pmproemail.php:647
2250
+ #: classes/class.pmproemail.php:696 classes/class.pmproemail.php:761
2251
+ #: classes/class.pmproemail.php:764
2252
+ msgid "Your membership has been cancelled"
2253
+ msgstr ""
2254
+
2255
+ #: classes/class.pmproemail.php:777 classes/class.pmproemail.php:815
2256
+ #: classes/class.pmproemail.php:651 classes/class.pmproemail.php:689
2257
+ #: classes/class.pmproemail.php:700 classes/class.pmproemail.php:738
2258
+ #: classes/class.pmproemail.php:765 classes/class.pmproemail.php:768
2259
+ #: classes/class.pmproemail.php:803 classes/class.pmproemail.php:806
2260
+ #, php-format
2261
+ msgid "This membership will expire on %s"
2262
+ msgstr ""
2263
+
2264
+ #: classes/class.pmproemail.php:781 classes/class.pmproemail.php:819
2265
+ #: classes/class.pmproemail.php:655 classes/class.pmproemail.php:693
2266
+ #: classes/class.pmproemail.php:704 classes/class.pmproemail.php:742
2267
+ #: classes/class.pmproemail.php:769 classes/class.pmproemail.php:772
2268
+ #: classes/class.pmproemail.php:807 classes/class.pmproemail.php:810
2269
+ msgid "This membership does not expire"
2270
+ msgstr ""
2271
+
2272
+ #: classes/class.pmproemail.php:805 classes/class.pmproemail.php:679
2273
+ #: classes/class.pmproemail.php:728 classes/class.pmproemail.php:793
2274
+ #: classes/class.pmproemail.php:796
2275
+ #, php-format
2276
+ msgid "Membership for %s at %s has been changed"
2277
+ msgstr ""
2278
+
2279
+ #: classes/class.pmproemail.php:811 classes/class.pmproemail.php:799
2280
+ #: classes/class.pmproemail.php:802
2281
+ msgid "Membership has been cancelled"
2282
+ msgstr ""
2283
+
2284
+ #: classes/gateways/class.pmprogateway.php:55
2285
+ #: classes/gateways/class.pmprogateway_authorizenet.php:171
2286
+ #: classes/gateways/class.pmprogateway_check.php:193
2287
+ #: classes/gateways/class.pmprogateway_cybersource.php:171
2288
+ #: classes/gateways/class.pmprogateway_payflowpro.php:164
2289
+ #: classes/gateways/class.pmprogateway_paypal.php:247
2290
+ #: classes/gateways/class.pmprogateway_authorizenet.php:55
2291
+ #: classes/gateways/class.pmprogateway_check.php:60
2292
+ #: classes/gateways/class.pmprogateway_cybersource.php:57
2293
+ #: classes/gateways/class.pmprogateway_payflowpro.php:27
2294
+ #: classes/gateways/class.pmprogateway_paypal.php:27
2295
+ msgid "Unknown error: Authorization failed."
2296
+ msgstr ""
2297
+
2298
+ #: classes/gateways/class.pmprogateway.php:106
2299
+ #: classes/gateways/class.pmprogateway.php:111
2300
+ #: classes/gateways/class.pmprogateway.php:129
2301
+ #: classes/gateways/class.pmprogateway_authorizenet.php:222
2302
+ #: classes/gateways/class.pmprogateway_authorizenet.php:227
2303
+ #: classes/gateways/class.pmprogateway_authorizenet.php:244
2304
+ #: classes/gateways/class.pmprogateway_check.php:244
2305
+ #: classes/gateways/class.pmprogateway_check.php:249
2306
+ #: classes/gateways/class.pmprogateway_check.php:267
2307
+ #: classes/gateways/class.pmprogateway_cybersource.php:222
2308
+ #: classes/gateways/class.pmprogateway_cybersource.php:227
2309
+ #: classes/gateways/class.pmprogateway_cybersource.php:245
2310
+ #: classes/gateways/class.pmprogateway_payflowpro.php:187
2311
+ #: classes/gateways/class.pmprogateway_payflowpro.php:192
2312
+ #: classes/gateways/class.pmprogateway_paypal.php:270
2313
+ #: classes/gateways/class.pmprogateway_authorizenet.php:106
2314
+ #: classes/gateways/class.pmprogateway_authorizenet.php:111
2315
+ #: classes/gateways/class.pmprogateway_authorizenet.php:128
2316
+ #: classes/gateways/class.pmprogateway_check.php:111
2317
+ #: classes/gateways/class.pmprogateway_check.php:116
2318
+ #: classes/gateways/class.pmprogateway_check.php:134
2319
+ #: classes/gateways/class.pmprogateway_cybersource.php:108
2320
+ #: classes/gateways/class.pmprogateway_cybersource.php:113
2321
+ #: classes/gateways/class.pmprogateway_cybersource.php:131
2322
+ #: classes/gateways/class.pmprogateway_payflowpro.php:50
2323
+ #: classes/gateways/class.pmprogateway_payflowpro.php:55
2324
+ #: classes/gateways/class.pmprogateway_paypal.php:50
2325
+ msgid "Unknown error: Payment failed."
2326
+ msgstr ""
2327
+
2328
+ #: classes/gateways/class.pmprogateway.php:113
2329
+ #: classes/gateways/class.pmprogateway_authorizenet.php:228
2330
+ #: classes/gateways/class.pmprogateway_check.php:251
2331
+ #: classes/gateways/class.pmprogateway_cybersource.php:229
2332
+ #: classes/gateways/class.pmprogateway_authorizenet.php:112
2333
+ #: classes/gateways/class.pmprogateway_check.php:118
2334
+ #: classes/gateways/class.pmprogateway_cybersource.php:115
2335
+ msgid ""
2336
+ "A partial payment was made that we could not void. Please contact the site owner "
2337
+ "immediately to correct this."
2338
+ msgstr ""
2339
+
2340
+ #: classes/gateways/class.pmprogateway_authorizenet.php:39 paid-memberships-pro.php:130
2341
+ #: paid-memberships-pro.php:122 paid-memberships-pro.php:123
2342
+ msgid "Authorize.net"
2343
+ msgstr ""
2344
+
2345
+ #: classes/gateways/class.pmprogateway_authorizenet.php:93
2346
+ msgid "Authorize.net Settings"
2347
+ msgstr ""
2348
+
2349
+ #: classes/gateways/class.pmprogateway_authorizenet.php:98
2350
+ #: adminpages/paymentsettings.php:260 adminpages/paymentsettings.php:264
2351
+ #: adminpages/paymentsettings.php:269
2352
+ msgid "Login Name"
2353
+ msgstr ""
2354
+
2355
+ #: classes/gateways/class.pmprogateway_authorizenet.php:106
2356
+ #: adminpages/paymentsettings.php:268 adminpages/paymentsettings.php:272
2357
+ #: adminpages/paymentsettings.php:277
2358
+ msgid "Transaction Key"
2359
+ msgstr ""
2360
+
2361
+ #: classes/gateways/class.pmprogateway_authorizenet.php:114
2362
+ #: adminpages/paymentsettings.php:454 adminpages/paymentsettings.php:495
2363
+ #: adminpages/paymentsettings.php:501 adminpages/paymentsettings.php:503
2364
+ msgid "Silent Post URL"
2365
+ msgstr ""
2366
+
2367
+ #: classes/gateways/class.pmprogateway_authorizenet.php:117
2368
+ #: adminpages/paymentsettings.php:457 adminpages/paymentsettings.php:498
2369
+ #: adminpages/paymentsettings.php:504 adminpages/paymentsettings.php:506
2370
+ msgid "To fully integrate with Authorize.net, be sure to set your Silent Post URL to"
2371
+ msgstr ""
2372
+
2373
+ #: classes/gateways/class.pmprogateway_authorizenet.php:908
2374
+ #: classes/gateways/class.pmprogateway_authorizenet.php:909
2375
+ #: classes/gateways/class.pmprogateway_authorizenet.php:787
2376
+ #: classes/gateways/class.pmprogateway_authorizenet.php:788
2377
+ #: classes/gateways/class.pmprogateway_authorizenet.php:789
2378
+ #: classes/gateways/class.pmprogateway_authorizenet.php:792
2379
+ #: classes/gateways/class.pmprogateway_authorizenet.php:793
2380
+ msgid "Could not connect to Authorize.net"
2381
+ msgstr ""
2382
+
2383
+ #: classes/gateways/class.pmprogateway_braintree.php:76 paid-memberships-pro.php:131
2384
+ #: classes/gateways/class.pmprogateway_braintree.php:63 paid-memberships-pro.php:123
2385
+ #: paid-memberships-pro.php:124
2386
+ msgid "Braintree Payments"
2387
+ msgstr ""
2388
+
2389
+ #: classes/gateways/class.pmprogateway_braintree.php:132
2390
+ #: classes/gateways/class.pmprogateway_braintree.php:119
2391
+ msgid "Braintree Settings"
2392
+ msgstr ""
2393
+
2394
+ #: classes/gateways/class.pmprogateway_braintree.php:137
2395
+ #: classes/gateways/class.pmprogateway_cybersource.php:106
2396
+ #: adminpages/paymentsettings.php:294 adminpages/paymentsettings.php:298
2397
+ #: adminpages/paymentsettings.php:303 adminpages/paymentsettings.php:364
2398
+ #: adminpages/paymentsettings.php:369
2399
+ #: classes/gateways/class.pmprogateway_braintree.php:124
2400
+ msgid "Merchant ID"
2401
+ msgstr ""
2402
+
2403
+ #: classes/gateways/class.pmprogateway_braintree.php:145
2404
+ #: adminpages/paymentsettings.php:302 adminpages/paymentsettings.php:306
2405
+ #: adminpages/paymentsettings.php:311
2406
+ #: classes/gateways/class.pmprogateway_braintree.php:132
2407
+ msgid "Public Key"
2408
+ msgstr ""
2409
+
2410
+ #: classes/gateways/class.pmprogateway_braintree.php:153
2411
+ #: adminpages/paymentsettings.php:310 adminpages/paymentsettings.php:314
2412
+ #: adminpages/paymentsettings.php:319
2413
+ #: classes/gateways/class.pmprogateway_braintree.php:140
2414
+ msgid "Private Key"
2415
+ msgstr ""
2416
+
2417
+ #: classes/gateways/class.pmprogateway_braintree.php:161
2418
+ #: adminpages/paymentsettings.php:318 adminpages/paymentsettings.php:322
2419
+ #: adminpages/paymentsettings.php:327
2420
+ #: classes/gateways/class.pmprogateway_braintree.php:148
2421
+ msgid "Client-Side Encryption Key"
2422
+ msgstr ""
2423
+
2424
+ #: classes/gateways/class.pmprogateway_braintree.php:169
2425
+ #: classes/gateways/class.pmprogateway_stripe.php:182 adminpages/paymentsettings.php:462
2426
+ #: adminpages/paymentsettings.php:470 adminpages/paymentsettings.php:503
2427
+ #: adminpages/paymentsettings.php:509 adminpages/paymentsettings.php:511
2428
+ #: adminpages/paymentsettings.php:517 adminpages/paymentsettings.php:519
2429
+ #: classes/gateways/class.pmprogateway_braintree.php:156
2430
+ #: classes/gateways/class.pmprogateway_stripe.php:181
2431
+ msgid "Web Hook URL"
2432
+ msgstr ""
2433
+
2434
+ #: classes/gateways/class.pmprogateway_braintree.php:173
2435
+ #: adminpages/paymentsettings.php:474 adminpages/paymentsettings.php:515
2436
+ #: adminpages/paymentsettings.php:521 adminpages/paymentsettings.php:523
2437
+ #: classes/gateways/class.pmprogateway_braintree.php:160
2438
+ msgid "To fully integrate with Braintree, be sure to set your Web Hook URL to"
2439
+ msgstr ""
2440
+
2441
+ #: classes/gateways/class.pmprogateway_braintree.php:283
2442
+ #: classes/gateways/class.pmprogateway_stripe.php:388 pages/checkout.php:494
2443
+ #: classes/gateways/class.pmprogateway_braintree.php:270
2444
+ #: classes/gateways/class.pmprogateway_stripe.php:387 pages/checkout.php:476
2445
+ #: pages/checkout.php:478 pages/checkout.php:485 pages/checkout.php:493
2446
+ #: pages/checkout.php:500
2447
+ msgid "Payment Information"
2448
+ msgstr ""
2449
+
2450
+ #: classes/gateways/class.pmprogateway_braintree.php:283
2451
+ #: classes/gateways/class.pmprogateway_stripe.php:388 pages/checkout.php:494
2452
+ #: classes/gateways/class.pmprogateway_braintree.php:270
2453
+ #: classes/gateways/class.pmprogateway_stripe.php:387 pages/checkout.php:476
2454
+ #: pages/checkout.php:478 pages/checkout.php:485 pages/checkout.php:493
2455
+ #: pages/checkout.php:500
2456
+ #, php-format
2457
+ msgid "We Accept %s"
2458
+ msgstr ""
2459
+
2460
+ #: classes/gateways/class.pmprogateway_braintree.php:316
2461
+ #: classes/gateways/class.pmprogateway_stripe.php:450 pages/billing.php:257
2462
+ #: pages/checkout.php:557 classes/gateways/class.pmprogateway_braintree.php:303
2463
+ #: classes/gateways/class.pmprogateway_stripe.php:449 pages/billing.php:244
2464
+ #: pages/billing.php:248 pages/checkout.php:503 pages/checkout.php:519
2465
+ #: pages/checkout.php:520 pages/checkout.php:527 pages/checkout.php:548
2466
+ msgid "Card Number"
2467
+ msgstr ""
2468
+
2469
+ #: classes/gateways/class.pmprogateway_braintree.php:353
2470
+ #: classes/gateways/class.pmprogateway_stripe.php:487 pages/billing.php:294
2471
+ #: pages/checkout.php:594 classes/gateways/class.pmprogateway_braintree.php:340
2472
+ #: classes/gateways/class.pmprogateway_stripe.php:486 pages/billing.php:281
2473
+ #: pages/billing.php:285 pages/checkout.php:540 pages/checkout.php:556
2474
+ #: pages/checkout.php:557 pages/checkout.php:564 pages/checkout.php:585
2475
+ msgid "CVV"
2476
+ msgstr ""
2477
+
2478
+ #: classes/gateways/class.pmprogateway_braintree.php:354
2479
+ #: classes/gateways/class.pmprogateway_stripe.php:488 pages/billing.php:295
2480
+ #: pages/checkout.php:595 classes/gateways/class.pmprogateway_braintree.php:341
2481
+ #: classes/gateways/class.pmprogateway_stripe.php:487 pages/billing.php:282
2482
+ #: pages/billing.php:286 pages/checkout.php:541 pages/checkout.php:557
2483
+ #: pages/checkout.php:558 pages/checkout.php:565 pages/checkout.php:586
2484
+ msgid "what's this?"
2485
+ msgstr ""
2486
+
2487
+ #: classes/gateways/class.pmprogateway_braintree.php:364
2488
+ #: classes/gateways/class.pmprogateway_stripe.php:498 pages/checkout.php:87
2489
+ #: pages/checkout.php:605 classes/gateways/class.pmprogateway_braintree.php:351
2490
+ #: classes/gateways/class.pmprogateway_stripe.php:497 pages/checkout.php:78
2491
+ #: pages/checkout.php:79 pages/checkout.php:80 pages/checkout.php:551
2492
+ #: pages/checkout.php:567 pages/checkout.php:568 pages/checkout.php:575
2493
+ #: pages/checkout.php:596
2494
+ msgid "Apply"
2495
+ msgstr ""
2496
+
2497
+ #: classes/gateways/class.pmprogateway_braintree.php:419
2498
+ #: classes/gateways/class.pmprogateway_stripe.php:1026
2499
+ #: classes/gateways/class.pmprogateway_braintree.php:61
2500
+ #: classes/gateways/class.pmprogateway_braintree.php:406
2501
+ #: classes/gateways/class.pmprogateway_stripe.php:53
2502
+ #: classes/gateways/class.pmprogateway_stripe.php:1011
2503
+ #: classes/gateways/class.pmprogateway_stripe.php:1025
2504
+ msgid "Unknown error: Initial payment failed."
2505
+ msgstr ""
2506
+
2507
+ #: classes/gateways/class.pmprogateway_braintree.php:478
2508
+ #: classes/gateways/class.pmprogateway_braintree.php:120
2509
+ #: classes/gateways/class.pmprogateway_braintree.php:465
2510
+ msgid "Error during settlement:"
2511
+ msgstr ""
2512
+
2513
+ #: classes/gateways/class.pmprogateway_braintree.php:487
2514
+ #: classes/gateways/class.pmprogateway_braintree.php:129
2515
+ #: classes/gateways/class.pmprogateway_braintree.php:474
2516
+ msgid "Error during charge:"
2517
+ msgstr ""
2518
+
2519
+ #: classes/gateways/class.pmprogateway_braintree.php:579
2520
+ #: classes/gateways/class.pmprogateway_braintree.php:198
2521
+ #: classes/gateways/class.pmprogateway_braintree.php:221
2522
+ #: classes/gateways/class.pmprogateway_braintree.php:566
2523
+ msgid "Failed to update customer."
2524
+ msgstr ""
2525
+
2526
+ #: classes/gateways/class.pmprogateway_braintree.php:627
2527
+ #: classes/gateways/class.pmprogateway_braintree.php:246
2528
+ #: classes/gateways/class.pmprogateway_braintree.php:269
2529
+ #: classes/gateways/class.pmprogateway_braintree.php:614
2530
+ msgid "Failed to create customer."
2531
+ msgstr ""
2532
+
2533
+ #: classes/gateways/class.pmprogateway_braintree.php:634
2534
+ #: classes/gateways/class.pmprogateway_braintree.php:253
2535
+ #: classes/gateways/class.pmprogateway_braintree.php:276
2536
+ #: classes/gateways/class.pmprogateway_braintree.php:621
2537
+ msgid "Error creating customer record with Braintree:"
2538
+ msgstr ""
2539
+
2540
+ #: classes/gateways/class.pmprogateway_braintree.php:734
2541
+ #: classes/gateways/class.pmprogateway_braintree.php:344
2542
+ #: classes/gateways/class.pmprogateway_braintree.php:345
2543
+ #: classes/gateways/class.pmprogateway_braintree.php:376
2544
+ #: classes/gateways/class.pmprogateway_braintree.php:721
2545
+ msgid "Error subscribing customer to plan with Braintree:"
2546
+ msgstr ""
2547
+
2548
+ #: classes/gateways/class.pmprogateway_braintree.php:749
2549
+ #: classes/gateways/class.pmprogateway_braintree.php:359
2550
+ #: classes/gateways/class.pmprogateway_braintree.php:360
2551
+ #: classes/gateways/class.pmprogateway_braintree.php:391
2552
+ #: classes/gateways/class.pmprogateway_braintree.php:736
2553
+ msgid "Failed to subscribe with Braintree:"
2554
+ msgstr ""
2555
+
2556
+ #: classes/gateways/class.pmprogateway_braintree.php:787
2557
+ #: classes/gateways/class.pmprogateway_braintree.php:800
2558
+ #: classes/gateways/class.pmprogateway_braintree.php:807
2559
+ #: classes/gateways/class.pmprogateway_braintree.php:397
2560
+ #: classes/gateways/class.pmprogateway_braintree.php:398
2561
+ #: classes/gateways/class.pmprogateway_braintree.php:410
2562
+ #: classes/gateways/class.pmprogateway_braintree.php:411
2563
+ #: classes/gateways/class.pmprogateway_braintree.php:417
2564
+ #: classes/gateways/class.pmprogateway_braintree.php:418
2565
+ #: classes/gateways/class.pmprogateway_braintree.php:429
2566
+ #: classes/gateways/class.pmprogateway_braintree.php:442
2567
+ #: classes/gateways/class.pmprogateway_braintree.php:449
2568
+ #: classes/gateways/class.pmprogateway_braintree.php:774
2569
+ #: classes/gateways/class.pmprogateway_braintree.php:794
2570
+ #: classes/gateways/class.pmprogateway_stripe.php:343
2571
+ #: classes/gateways/class.pmprogateway_stripe.php:344
2572
+ #: classes/gateways/class.pmprogateway_stripe.php:351
2573
+ #: classes/gateways/class.pmprogateway_stripe.php:353
2574
+ #: classes/gateways/class.pmprogateway_stripe.php:354
2575
+ #: classes/gateways/class.pmprogateway_stripe.php:361
2576
+ #: classes/gateways/class.pmprogateway_stripe.php:396
2577
+ #: classes/gateways/class.pmprogateway_stripe.php:402
2578
+ #: classes/gateways/class.pmprogateway_stripe.php:423
2579
+ msgid "Could not find the subscription."
2580
+ msgstr ""
2581
+
2582
+ #: classes/gateways/class.pmprogateway_check.php:48 paid-memberships-pro.php:124
2583
+ #: adminpages/orders.php:399 adminpages/orders.php:449
2584
+ #: adminpages/paymentsettings.php:157 adminpages/paymentsettings.php:159
2585
+ #: paid-memberships-pro.php:116 paid-memberships-pro.php:117
2586
+ msgid "Pay by Check"
2587
+ msgstr ""
2588
+
2589
+ #: classes/gateways/class.pmprogateway_check.php:100
2590
+ msgid "Pay by Check Settings"
2591
+ msgstr ""
2592
+
2593
+ #: classes/gateways/class.pmprogateway_check.php:105 adminpages/paymentsettings.php:389
2594
+ #: adminpages/paymentsettings.php:415 adminpages/paymentsettings.php:420
2595
+ #: adminpages/paymentsettings.php:422
2596
+ msgid "Instructions"
2597
+ msgstr ""
2598
+
2599
+ #: classes/gateways/class.pmprogateway_check.php:109 adminpages/paymentsettings.php:393
2600
+ #: adminpages/paymentsettings.php:419 adminpages/paymentsettings.php:424
2601
+ #: adminpages/paymentsettings.php:426
2602
+ msgid ""
2603
+ "Who to write the check out to. Where to mail it. Shown on checkout, confirmation, and "
2604
+ "invoice pages."
2605
+ msgstr ""
2606
+
2607
+ #: classes/gateways/class.pmprogateway_cybersource.php:42
2608
+ msgid "CyberSource"
2609
+ msgstr ""
2610
+
2611
+ #: classes/gateways/class.pmprogateway_cybersource.php:96
2612
+ msgid "CyberSource Settings"
2613
+ msgstr ""
2614
+
2615
+ #: classes/gateways/class.pmprogateway_cybersource.php:101
2616
+ #: adminpages/paymentsettings.php:174
2617
+ msgid ""
2618
+ "This gateway option is in beta. Some functionality may not be available. Please "
2619
+ "contact Paid Memberships Pro with any issues you run into. <strong>Please be sure to "
2620
+ "upgrade Paid Memberships Pro to the latest versions when available.</strong>"
2621
+ msgstr ""
2622
+
2623
+ #: classes/gateways/class.pmprogateway_cybersource.php:114
2624
+ #: adminpages/paymentsettings.php:372 adminpages/paymentsettings.php:377
2625
+ msgid "Transaction Security Key"
2626
+ msgstr ""
2627
+
2628
+ #: classes/gateways/class.pmprogateway_payflowpro.php:39
2629
+ msgid "Payflow Pro/PayPal Pro"
2630
+ msgstr ""
2631
+
2632
+ #: classes/gateways/class.pmprogateway_payflowpro.php:95
2633
+ msgid "Payflow Pro Settings"
2634
+ msgstr ""
2635
+
2636
+ #: classes/gateways/class.pmprogateway_payflowpro.php:100
2637
+ #: adminpages/paymentsettings.php:195 adminpages/paymentsettings.php:199
2638
+ #: adminpages/paymentsettings.php:204
2639
+ msgid "Partner"
2640
+ msgstr ""
2641
+
2642
+ #: classes/gateways/class.pmprogateway_payflowpro.php:108
2643
+ #: adminpages/paymentsettings.php:203 adminpages/paymentsettings.php:207
2644
+ #: adminpages/paymentsettings.php:212
2645
+ msgid "Vendor"
2646
+ msgstr ""
2647
+
2648
+ #: classes/gateways/class.pmprogateway_payflowpro.php:124 pages/checkout.php:189
2649
+ #: adminpages/paymentsettings.php:219 adminpages/paymentsettings.php:223
2650
+ #: adminpages/paymentsettings.php:228 pages/checkout.php:177 pages/checkout.php:180
2651
+ #: pages/checkout.php:182
2652
+ msgid "Password"
2653
+ msgstr ""
2654
+
2655
+ #: classes/gateways/class.pmprogateway_payflowpro.php:132
2656
+ msgid "IPN Handler"
2657
+ msgstr ""
2658
+
2659
+ #: classes/gateways/class.pmprogateway_payflowpro.php:137
2660
+ #, php-format
2661
+ msgid ""
2662
+ "Payflow does not use IPN. To sync recurring subscriptions, please see <a target="
2663
+ "\"_blank\" href=\"%s\">this addon</a>."
2664
+ msgstr ""
2665
+
2666
+ #: classes/gateways/class.pmprogateway_payflowpro.php:194
2667
+ #: classes/gateways/class.pmprogateway_paypal.php:277
2668
+ #: classes/gateways/class.pmprogateway_payflowpro.php:57
2669
+ #: classes/gateways/class.pmprogateway_paypal.php:57
2670
+ msgid ""
2671
+ "A partial payment was made that we could not refund. Please contact the site owner "
2672
+ "immediately to correct this."
2673
+ msgstr ""
2674
+
2675
+ #: classes/gateways/class.pmprogateway_paypal.php:57 paid-memberships-pro.php:127
2676
+ #: paid-memberships-pro.php:119 paid-memberships-pro.php:120
2677
+ msgid "PayPal Website Payments Pro"
2678
+ msgstr ""
2679
+
2680
+ #: classes/gateways/class.pmprogateway_paypal.php:113
2681
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:128
2682
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:112
2683
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:118
2684
+ msgid "PayPal Settings"
2685
+ msgstr ""
2686
+
2687
+ #: classes/gateways/class.pmprogateway_paypal.php:118
2688
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:133
2689
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:117
2690
+ #: adminpages/paymentsettings.php:179
2691
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:123
2692
+ msgid ""
2693
+ "We do not recommend using PayPal Standard. We suggest using PayPal Express, Website "
2694
+ "Payments Pro (Legacy), or PayPal Pro (Payflow Pro). <a target=\"_blank\" href="
2695
+ "\"http://www.paidmembershipspro.com/2013/09/read-using-paypal-standard-paid-"
2696
+ "memberships-pro/\">More information on why can be found here.</a>"
2697
+ msgstr ""
2698
+
2699
+ #: classes/gateways/class.pmprogateway_paypal.php:123
2700
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:138
2701
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:122
2702
+ #: adminpages/paymentsettings.php:227 adminpages/paymentsettings.php:231
2703
+ #: adminpages/paymentsettings.php:236
2704
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:128
2705
+ msgid "Gateway Account Email"
2706
+ msgstr ""
2707
+
2708
+ #: classes/gateways/class.pmprogateway_paypal.php:131
2709
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:146
2710
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:130
2711
+ #: classes/gateways/class.pmprogateway_twocheckout.php:121
2712
+ #: adminpages/paymentsettings.php:235 adminpages/paymentsettings.php:239
2713
+ #: adminpages/paymentsettings.php:244 adminpages/paymentsettings.php:331
2714
+ #: adminpages/paymentsettings.php:336
2715
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:136
2716
+ #: classes/gateways/class.pmprogateway_twocheckout.php:113
2717
+ msgid "API Username"
2718
+ msgstr ""
2719
+
2720
+ #: classes/gateways/class.pmprogateway_paypal.php:139
2721
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:154
2722
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:138
2723
+ #: classes/gateways/class.pmprogateway_twocheckout.php:130
2724
+ #: adminpages/paymentsettings.php:243 adminpages/paymentsettings.php:247
2725
+ #: adminpages/paymentsettings.php:252 adminpages/paymentsettings.php:339
2726
+ #: adminpages/paymentsettings.php:344
2727
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:144
2728
+ #: classes/gateways/class.pmprogateway_twocheckout.php:121
2729
+ msgid "API Password"
2730
+ msgstr ""
2731
+
2732
+ #: classes/gateways/class.pmprogateway_paypal.php:147
2733
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:162
2734
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:146
2735
+ #: adminpages/paymentsettings.php:251 adminpages/paymentsettings.php:255
2736
+ #: adminpages/paymentsettings.php:260
2737
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:152
2738
+ msgid "API Signature"
2739
+ msgstr ""
2740
+
2741
+ #: classes/gateways/class.pmprogateway_paypal.php:155
2742
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:170
2743
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:154
2744
+ #: adminpages/paymentsettings.php:446 adminpages/paymentsettings.php:479
2745
+ #: adminpages/paymentsettings.php:485 adminpages/paymentsettings.php:487
2746
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:160
2747
+ msgid "IPN Handler URL"
2748
+ msgstr ""
2749
+
2750
+ #: classes/gateways/class.pmprogateway_paypal.php:158
2751
+ msgid ""
2752
+ "This URL is passed to PayPal for all new charges and subscriptions. You SHOULD NOT "
2753
+ "set this in your PayPal account settings."
2754
+ msgstr ""
2755
+
2756
+ #: classes/gateways/class.pmprogateway_paypal.php:178
2757
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:412
2758
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:202 pages/checkout.php:295
2759
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:402 pages/checkout.php:286
2760
+ #: pages/checkout.php:288 pages/checkout.php:302 pages/checkout.php:309
2761
+ #: pages/checkout.php:675 pages/checkout.php:682 pages/checkout.php:685
2762
+ #: pages/checkout.php:701
2763
+ msgid "Check Out with PayPal"
2764
+ msgstr ""
2765
+
2766
+ #: classes/gateways/class.pmprogateway_paypal.php:184
2767
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:418
2768
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:208 pages/checkout.php:713
2769
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:408 pages/checkout.php:681
2770
+ #: pages/checkout.php:688 pages/checkout.php:691 pages/checkout.php:704
2771
+ #: pages/checkout.php:707
2772
+ msgid "Submit and Check Out"
2773
+ msgstr ""
2774
+
2775
+ #: classes/gateways/class.pmprogateway_paypal.php:184
2776
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:418
2777
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:208
2778
+ #: classes/gateways/class.pmprogateway_twocheckout.php:214 pages/checkout.php:713
2779
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:408
2780
+ #: classes/gateways/class.pmprogateway_twocheckout.php:192 pages/checkout.php:681
2781
+ #: pages/checkout.php:688 pages/checkout.php:691 pages/checkout.php:704
2782
+ #: pages/checkout.php:707
2783
+ msgid "Submit and Confirm"
2784
+ msgstr ""
2785
+
2786
+ #: classes/gateways/class.pmprogateway_paypal.php:605
2787
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:750
2788
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:466
2789
+ #: classes/gateways/class.pmprogateway_paypal.php:385
2790
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:301
2791
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:303
2792
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:305
2793
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:731
2794
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:740
2795
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:216
2796
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:220
2797
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:230
2798
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:231
2799
+ msgid ""
2800
+ "Please contact the site owner or cancel your subscription from within PayPal to make "
2801
+ "sure you are not charged going forward."
2802
+ msgstr ""
2803
+
2804
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:73 paid-memberships-pro.php:126
2805
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:63 paid-memberships-pro.php:118
2806
+ #: paid-memberships-pro.php:119
2807
+ msgid "PayPal Express"
2808
+ msgstr ""
2809
+
2810
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:173
2811
+ #: adminpages/paymentsettings.php:449 adminpages/paymentsettings.php:482
2812
+ #: adminpages/paymentsettings.php:488 adminpages/paymentsettings.php:490
2813
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:163
2814
+ msgid "To fully integrate with PayPal, be sure to set your IPN Handler URL to "
2815
+ msgstr ""
2816
+
2817
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:278
2818
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:330
2819
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:268
2820
+ #: classes/gateways/class.pmprogateway_paypalexpress.php:320 preheaders/checkout.php:690
2821
+ #: preheaders/checkout.php:697 preheaders/checkout.php:702 preheaders/checkout.php:735
2822
+ #: preheaders/checkout.php:750 preheaders/checkout.php:753 preheaders/checkout.php:754
2823
+ #: preheaders/checkout.php:757 preheaders/checkout.php:762 preheaders/checkout.php:803
2824
+ #: preheaders/checkout.php:822 preheaders/checkout.php:823
2825
+ msgid "The PayPal Token was lost."
2826
+ msgstr ""
2827
+
2828
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:60
2829
+ #: paid-memberships-pro.php:129 paid-memberships-pro.php:121
2830
+ #: paid-memberships-pro.php:122
2831
+ msgid "PayPal Standard"
2832
+ msgstr ""
2833
+
2834
+ #: classes/gateways/class.pmprogateway_paypalstandard.php:157
2835
+ msgid ""
2836
+ "Here is your IPN URL for reference. You SHOULD NOT set this in your PayPal settings."
2837
+ msgstr ""
2838
+
2839
+ #: classes/gateways/class.pmprogateway_stripe.php:94 paid-memberships-pro.php:125
2840
+ #: classes/gateways/class.pmprogateway_stripe.php:93 paid-memberships-pro.php:117
2841
+ #: paid-memberships-pro.php:118
2842
+ msgid "Stripe"
2843
+ msgstr ""
2844
+
2845
+ #: classes/gateways/class.pmprogateway_stripe.php:149
2846
+ #: classes/gateways/class.pmprogateway_stripe.php:148
2847
+ msgid "Stripe Settings"
2848
+ msgstr ""
2849
+
2850
+ #: classes/gateways/class.pmprogateway_stripe.php:154 adminpages/paymentsettings.php:277
2851
+ #: adminpages/paymentsettings.php:281 adminpages/paymentsettings.php:286
2852
+ #: classes/gateways/class.pmprogateway_stripe.php:153
2853
+ msgid "Secret Key"
2854
+ msgstr ""
2855
+
2856
+ #: classes/gateways/class.pmprogateway_stripe.php:162 adminpages/paymentsettings.php:285
2857
+ #: adminpages/paymentsettings.php:289 adminpages/paymentsettings.php:294
2858
+ #: classes/gateways/class.pmprogateway_stripe.php:161
2859
+ msgid "Publishable Key"
2860
+ msgstr ""
2861
+
2862
+ #: classes/gateways/class.pmprogateway_stripe.php:170 adminpages/paymentsettings.php:425
2863
+ #: adminpages/paymentsettings.php:430 adminpages/paymentsettings.php:432
2864
+ #: classes/gateways/class.pmprogateway_stripe.php:169
2865
+ msgid "Show Billing Address Fields"
2866
+ msgstr ""
2867
+
2868
+ #: classes/gateways/class.pmprogateway_stripe.php:177 adminpages/paymentsettings.php:437
2869
+ #: adminpages/paymentsettings.php:439 classes/gateways/class.pmprogateway_stripe.php:176
2870
+ msgid ""
2871
+ "Stripe doesn't require billing address fields. Choose 'No' to hide them on the "
2872
+ "checkout page.<br /><strong>If No, make sure you disable address verification in the "
2873
+ "Stripe dashboard settings.</strong>"
2874
+ msgstr ""
2875
+
2876
+ #: classes/gateways/class.pmprogateway_stripe.php:185 adminpages/paymentsettings.php:465
2877
+ #: adminpages/paymentsettings.php:506 adminpages/paymentsettings.php:512
2878
+ #: adminpages/paymentsettings.php:514 classes/gateways/class.pmprogateway_stripe.php:184
2879
+ msgid "To fully integrate with Stripe, be sure to set your Web Hook URL to"
2880
+ msgstr ""
2881
+
2882
+ #: classes/gateways/class.pmprogateway_stripe.php:568
2883
+ #: classes/gateways/class.pmprogateway_stripe.php:567
2884
+ msgid "Subscription Updates"
2885
+ msgstr ""
2886
+
2887
+ #: classes/gateways/class.pmprogateway_stripe.php:572
2888
+ #: classes/gateways/class.pmprogateway_stripe.php:571
2889
+ msgid ""
2890
+ "Subscription updates, allow you to change the member's subscription values at "
2891
+ "predefined times. Be sure to click Update Profile after making changes."
2892
+ msgstr ""
2893
+
2894
+ #: classes/gateways/class.pmprogateway_stripe.php:574
2895
+ #: classes/gateways/class.pmprogateway_stripe.php:573
2896
+ msgid ""
2897
+ "Subscription updates, allow you to change the member's subscription values at "
2898
+ "predefined times. Be sure to click Update User after making changes."
2899
+ msgstr ""
2900
+
2901
+ #: classes/gateways/class.pmprogateway_stripe.php:579 pages/billing.php:338
2902
+ #: classes/gateways/class.pmprogateway_stripe.php:578 pages/billing.php:294
2903
+ #: pages/billing.php:298 pages/billing.php:329
2904
+ msgid "Update"
2905
+ msgstr ""
2906
+
2907
+ #: classes/gateways/class.pmprogateway_stripe.php:770
2908
+ #: classes/gateways/class.pmprogateway_stripe.php:769
2909
+ msgid "Could not cancel the old subscription. Updates have not been processed."
2910
+ msgstr ""
2911
+
2912
+ #: classes/gateways/class.pmprogateway_stripe.php:1204
2913
+ #: classes/gateways/class.pmprogateway_stripe.php:190
2914
+ #: classes/gateways/class.pmprogateway_stripe.php:192
2915
+ #: classes/gateways/class.pmprogateway_stripe.php:199
2916
+ #: classes/gateways/class.pmprogateway_stripe.php:201
2917
+ #: classes/gateways/class.pmprogateway_stripe.php:1187
2918
+ #: classes/gateways/class.pmprogateway_stripe.php:1188
2919
+ #: classes/gateways/class.pmprogateway_stripe.php:1202
2920
+ #: classes/gateways/class.pmprogateway_stripe.php:1203
2921
+ msgid "Error creating customer record with Stripe:"
2922
+ msgstr ""
2923
+
2924
+ #: classes/gateways/class.pmprogateway_stripe.php:1261
2925
+ #: classes/gateways/class.pmprogateway_stripe.php:1411
2926
+ #: classes/gateways/class.pmprogateway_stripe.php:278
2927
+ #: classes/gateways/class.pmprogateway_stripe.php:279
2928
+ #: classes/gateways/class.pmprogateway_stripe.php:286
2929
+ #: classes/gateways/class.pmprogateway_stripe.php:302
2930
+ #: classes/gateways/class.pmprogateway_stripe.php:308
2931
+ #: classes/gateways/class.pmprogateway_stripe.php:311
2932
+ #: classes/gateways/class.pmprogateway_stripe.php:1244
2933
+ #: classes/gateways/class.pmprogateway_stripe.php:1245
2934
+ #: classes/gateways/class.pmprogateway_stripe.php:1259
2935
+ #: classes/gateways/class.pmprogateway_stripe.php:1260
2936
+ #: classes/gateways/class.pmprogateway_stripe.php:1390
2937
+ #: classes/gateways/class.pmprogateway_stripe.php:1391
2938
+ #: classes/gateways/class.pmprogateway_stripe.php:1409
2939
+ #: classes/gateways/class.pmprogateway_stripe.php:1410
2940
+ msgid "Error creating plan with Stripe:"
2941
+ msgstr ""
2942
+
2943
+ #: classes/gateways/class.pmprogateway_stripe.php:1442
2944
+ #: classes/gateways/class.pmprogateway_stripe.php:294
2945
+ #: classes/gateways/class.pmprogateway_stripe.php:295
2946
+ #: classes/gateways/class.pmprogateway_stripe.php:302
2947
+ #: classes/gateways/class.pmprogateway_stripe.php:318
2948
+ #: classes/gateways/class.pmprogateway_stripe.php:324
2949
+ #: classes/gateways/class.pmprogateway_stripe.php:330
2950
+ #: classes/gateways/class.pmprogateway_stripe.php:1420
2951
+ #: classes/gateways/class.pmprogateway_stripe.php:1421
2952
+ #: classes/gateways/class.pmprogateway_stripe.php:1422
2953
+ #: classes/gateways/class.pmprogateway_stripe.php:1440
2954
+ #: classes/gateways/class.pmprogateway_stripe.php:1441
2955
+ msgid "Error subscribing customer to plan with Stripe:"
2956
+ msgstr ""
2957
+
2958
+ #: classes/gateways/class.pmprogateway_stripe.php:1538
2959
+ #: classes/gateways/class.pmprogateway_stripe.php:383
2960
+ #: classes/gateways/class.pmprogateway_stripe.php:389
2961
+ #: classes/gateways/class.pmprogateway_stripe.php:410
2962
+ #: classes/gateways/class.pmprogateway_stripe.php:1516
2963
+ #: classes/gateways/class.pmprogateway_stripe.php:1517
2964
+ #: classes/gateways/class.pmprogateway_stripe.php:1518
2965
+ #: classes/gateways/class.pmprogateway_stripe.php:1536
2966
+ #: classes/gateways/class.pmprogateway_stripe.php:1537
2967
+ msgid "Could not cancel old subscription."
2968
+ msgstr ""
2969
+
2970
+ #: classes/gateways/class.pmprogateway_stripe.php:1555
2971
+ #: classes/gateways/class.pmprogateway_stripe.php:1533
2972
+ #: classes/gateways/class.pmprogateway_stripe.php:1534
2973
+ #: classes/gateways/class.pmprogateway_stripe.php:1535
2974
+ #: classes/gateways/class.pmprogateway_stripe.php:1553
2975
+ #: classes/gateways/class.pmprogateway_stripe.php:1554
2976
+ msgid "Could not find the customer."
2977
+ msgstr ""
2978
+
2979
+ #: classes/gateways/class.pmprogateway_twocheckout.php:60 paid-memberships-pro.php:132
2980
+ #: classes/gateways/class.pmprogateway_twocheckout.php:53 paid-memberships-pro.php:124
2981
+ #: paid-memberships-pro.php:125
2982
+ msgid "2Checkout"
2983
+ msgstr ""
2984
+
2985
+ #: classes/gateways/class.pmprogateway_twocheckout.php:116
2986
+ #: classes/gateways/class.pmprogateway_twocheckout.php:108
2987
+ msgid "2Checkout Settings"
2988
+ msgstr ""
2989
+
2990
+ #: classes/gateways/class.pmprogateway_twocheckout.php:125
2991
+ msgid ""
2992
+ "Go to Account &raquo; User Management in 2Checkout and create a user with API Access "
2993
+ "and API Updating."
2994
+ msgstr ""
2995
+
2996
+ #: classes/gateways/class.pmprogateway_twocheckout.php:134
2997
+ msgid "Password for the API user created."
2998
+ msgstr ""
2999
+
3000
+ #: classes/gateways/class.pmprogateway_twocheckout.php:139
3001
+ msgid "API Private Key"
3002
+ msgstr ""
3003
+
3004
+ #: classes/gateways/class.pmprogateway_twocheckout.php:143
3005
+ msgid "Go to API in 2Checkout and generate a new key pair. Paste the Private Key here."
3006
+ msgstr ""
3007
+
3008
+ #: classes/gateways/class.pmprogateway_twocheckout.php:152
3009
+ msgid "Click on the profile icon in 2Checkout to find your Account Number."
3010
+ msgstr ""
3011
+
3012
+ #: classes/gateways/class.pmprogateway_twocheckout.php:157
3013
+ #: adminpages/paymentsettings.php:355 adminpages/paymentsettings.php:360
3014
+ #: classes/gateways/class.pmprogateway_twocheckout.php:137
3015
+ msgid "Secret Word"
3016
+ msgstr ""
3017
+
3018
+ #: classes/gateways/class.pmprogateway_twocheckout.php:161
3019
+ msgid ""
3020
+ "Go to Account &raquo; Site Management. Look under Checkout Options to find the Secret "
3021
+ "Word."
3022
+ msgstr ""
3023
+
3024
+ #: classes/gateways/class.pmprogateway_twocheckout.php:166
3025
+ #: adminpages/paymentsettings.php:487 adminpages/paymentsettings.php:493
3026
+ #: adminpages/paymentsettings.php:495
3027
+ #: classes/gateways/class.pmprogateway_twocheckout.php:145
3028
+ msgid "TwoCheckout INS URL"
3029
+ msgstr ""
3030
+
3031
+ #: classes/gateways/class.pmprogateway_twocheckout.php:169
3032
+ msgid ""
3033
+ "To fully integrate with 2Checkout, be sure to use the following for your INS URL and "
3034
+ "Approved URL"
3035
+ msgstr ""
3036
+
3037
+ #: classes/gateways/class.pmprogateway_twocheckout.php:214
3038
+ #: classes/gateways/class.pmprogateway_twocheckout.php:192
3039
+ msgid "Check Out with 2Checkout"
3040
+ msgstr ""
3041
+
3042
+ #: includes/adminpages.php:47 includes/adminpages.php:9 includes/adminpages.php:39
3043
+ #: includes/adminpages.php:93 includes/adminpages.php:100
3044
+ msgid "Memberships"
3045
+ msgstr ""
3046
+
3047
+ #: includes/adminpages.php:48 includes/adminpages.php:118 includes/adminpages.php:10
3048
+ #: includes/adminpages.php:49 includes/adminpages.php:107 includes/adminpages.php:114
3049
+ msgid "Page Settings"
3050
+ msgstr ""
3051
+
3052
+ #: includes/adminpages.php:49 includes/adminpages.php:125 includes/adminpages.php:11
3053
+ #: includes/adminpages.php:54 includes/adminpages.php:114 includes/adminpages.php:121
3054
+ msgid "Payment Settings"
3055
+ msgstr ""
3056
+
3057
+ #: includes/adminpages.php:54 includes/adminpages.php:160 includes/adminpages.php:16
3058
+ #: includes/adminpages.php:79 includes/adminpages.php:149 includes/adminpages.php:156
3059
+ msgid "Reports"
3060
+ msgstr ""
3061
+
3062
+ #: includes/adminpages.php:56 includes/adminpages.php:174 includes/adminpages.php:18
3063
+ #: includes/adminpages.php:89 includes/adminpages.php:163 includes/adminpages.php:170
3064
+ msgid "Discount Codes"
3065
+ msgstr "Các Mã Giảm Giá"
3066
+
3067
+ #: includes/adminpages.php:104 includes/adminpages.php:100
3068
+ msgid "<span class=\"ab-icon\"></span>Memberships"
3069
+ msgstr ""
3070
+
3071
+ #: includes/adminpages.php:265 includes/adminpages.php:261
3072
+ msgid "Docs"
3073
+ msgstr ""
3074
+
3075
+ #: includes/adminpages.php:265 includes/adminpages.php:261
3076
+ msgid "View PMPro Documentation"
3077
+ msgstr ""
3078
+
3079
+ #: includes/adminpages.php:266 includes/adminpages.php:262
3080
+ msgid "Support"
3081
+ msgstr "Hỗ trợ"
3082
+
3083
+ #: includes/adminpages.php:266 includes/adminpages.php:262
3084
+ msgid "Visit Customer Support Forum"
3085
+ msgstr "Xem Diên Dàn Hỗ Trợ"
3086
+
3087
+ #: includes/currencies.php:7 includes/currencies.php:75 includes/currencies.php:37
3088
+ #: includes/currencies.php:44 includes/currencies.php:64 includes/currencies.php:68
3089
+ msgid "US Dollars (&#36;)"
3090
+ msgstr ""
3091
+
3092
+ #: includes/currencies.php:9 includes/currencies.php:78 includes/currencies.php:8
3093
+ #: includes/currencies.php:40 includes/currencies.php:47 includes/currencies.php:67
3094
+ #: includes/currencies.php:71
3095
+ msgid "Euros (&euro;)"
3096
+ msgstr ""
3097
+
3098
+ #: includes/currencies.php:14 includes/currencies.php:77 includes/currencies.php:9
3099
+ #: includes/currencies.php:39 includes/currencies.php:46 includes/currencies.php:66
3100
+ #: includes/currencies.php:70
3101
+ msgid "Pounds Sterling (&pound;)"
3102
+ msgstr ""
3103
+
3104
+ #: includes/currencies.php:18 includes/currencies.php:10
3105
+ msgid "Australian Dollars (&#36;)"
3106
+ msgstr ""
3107
+
3108
+ #: includes/currencies.php:20
3109
+ msgid "Brazilian Real (R&#36;)"
3110
+ msgstr ""
3111
+
3112
+ #: includes/currencies.php:24 includes/currencies.php:76 includes/currencies.php:12
3113
+ #: includes/currencies.php:38 includes/currencies.php:45 includes/currencies.php:65
3114
+ #: includes/currencies.php:69
3115
+ msgid "Canadian Dollars (&#36;)"
3116
+ msgstr ""
3117
+
3118
+ #: includes/currencies.php:25 includes/currencies.php:13
3119
+ msgid "Chinese Yuan"
3120
+ msgstr ""
3121
+
3122
+ #: includes/currencies.php:27 includes/currencies.php:13 includes/currencies.php:14
3123
+ #: includes/currencies.php:26
3124
+ msgid "Czech Koruna"
3125
+ msgstr ""
3126
+
3127
+ #: includes/currencies.php:34 includes/currencies.php:14 includes/currencies.php:15
3128
+ #: includes/currencies.php:27
3129
+ msgid "Danish Krone"
3130
+ msgstr ""
3131
+
3132
+ #: includes/currencies.php:35 includes/currencies.php:15 includes/currencies.php:16
3133
+ #: includes/currencies.php:28
3134
+ msgid "Hong Kong Dollar (&#36;)"
3135
+ msgstr ""
3136
+
3137
+ #: includes/currencies.php:36 includes/currencies.php:16 includes/currencies.php:17
3138
+ #: includes/currencies.php:29
3139
+ msgid "Hungarian Forint"
3140
+ msgstr ""
3141
+
3142
+ #: includes/currencies.php:37 includes/currencies.php:18 includes/currencies.php:30
3143
+ msgid "Indian Rupee"
3144
+ msgstr ""
3145
+
3146
+ #: includes/currencies.php:38 includes/currencies.php:19 includes/currencies.php:31
3147
+ msgid "Indonesia Rupiah"
3148
+ msgstr ""
3149
+
3150
+ #: includes/currencies.php:39 includes/currencies.php:17 includes/currencies.php:20
3151
+ #: includes/currencies.php:32
3152
+ msgid "Israeli Shekel"
3153
+ msgstr ""
3154
+
3155
+ #: includes/currencies.php:41 includes/currencies.php:18 includes/currencies.php:21
3156
+ #: includes/currencies.php:34
3157
+ msgid "Japanese Yen (&yen;)"
3158
+ msgstr ""
3159
+
3160
+ #: includes/currencies.php:45 includes/currencies.php:19 includes/currencies.php:22
3161
+ #: includes/currencies.php:38
3162
+ msgid "Malaysian Ringgits"
3163
+ msgstr ""
3164
+
3165
+ #: includes/currencies.php:46 includes/currencies.php:20 includes/currencies.php:23
3166
+ #: includes/currencies.php:39
3167
+ msgid "Mexican Peso (&#36;)"
3168
+ msgstr ""
3169
+
3170
+ #: includes/currencies.php:47 includes/currencies.php:21 includes/currencies.php:24
3171
+ #: includes/currencies.php:40
3172
+ msgid "New Zealand Dollar (&#36;)"
3173
+ msgstr "New Zealand Dollar (&#36;)"
3174
+
3175
+ #: includes/currencies.php:48 includes/currencies.php:22 includes/currencies.php:25
3176
+ #: includes/currencies.php:41
3177
+ msgid "Norwegian Krone"
3178
+ msgstr "Norwegian Krone"
3179
+
3180
+ #: includes/currencies.php:49 includes/currencies.php:23 includes/currencies.php:26
3181
+ #: includes/currencies.php:42
3182
+ msgid "Philippine Pesos"
3183
+ msgstr "Philippine Pesos"
3184
+
3185
+ #: includes/currencies.php:50 includes/currencies.php:24 includes/currencies.php:27
3186
+ #: includes/currencies.php:43
3187
+ msgid "Polish Zloty"
3188
+ msgstr "Polish Zloty"
3189
+
3190
+ #: includes/currencies.php:52 includes/currencies.php:25 includes/currencies.php:28
3191
+ #: includes/currencies.php:45
3192
+ msgid "Singapore Dollar (&#36;)"
3193
+ msgstr "Singapore Dollar (&#36;)"
3194
+
3195
+ #: includes/currencies.php:57 includes/currencies.php:50
3196
+ msgid "South African Rand (R)"
3197
+ msgstr "South African Rand (R)"
3198
+
3199
+ #: includes/currencies.php:61 includes/currencies.php:30 includes/currencies.php:50
3200
+ #: includes/currencies.php:54
3201
+ msgid "South Korean Won"
3202
+ msgstr "South Korean Won"
3203
+
3204
+ #: includes/currencies.php:62 includes/currencies.php:26 includes/currencies.php:31
3205
+ #: includes/currencies.php:51 includes/currencies.php:55
3206
+ msgid "Swedish Krona"
3207
+ msgstr "Swedish Krona"
3208
+
3209
+ #: includes/currencies.php:63 includes/currencies.php:27 includes/currencies.php:32
3210
+ #: includes/currencies.php:52 includes/currencies.php:56
3211
+ msgid "Swiss Franc"
3212
+ msgstr "Swiss Franc"
3213
+
3214
+ #: includes/currencies.php:64 includes/currencies.php:28 includes/currencies.php:33
3215
+ #: includes/currencies.php:53 includes/currencies.php:57
3216
+ msgid "Taiwan New Dollars"
3217
+ msgstr "Taiwan New Dollars"
3218
+
3219
+ #: includes/currencies.php:65 includes/currencies.php:29 includes/currencies.php:34
3220
+ #: includes/currencies.php:54 includes/currencies.php:58
3221
+ msgid "Thai Baht"
3222
+ msgstr "Thai Baht"
3223
+
3224
+ #: includes/currencies.php:66 includes/currencies.php:35 includes/currencies.php:55
3225
+ #: includes/currencies.php:59
3226
+ msgid "Turkish Lira"
3227
+ msgstr "Turkish Lira"
3228
+
3229
+ #: includes/currencies.php:67 includes/currencies.php:36 includes/currencies.php:56
3230
+ #: includes/currencies.php:60
3231
+ msgid "Vietnamese Dong"
3232
+ msgstr "VND"
3233
+
3234
+ #: includes/functions.php:200 includes/functions.php:160 includes/functions.php:196
3235
+ #: includes/functions.php:202 includes/functions.php:203 includes/functions.php:204
3236
+ #: includes/functions.php:207
3237
+ #, php-format
3238
+ msgid "The price for membership is <strong>%s</strong> now"
3239
+ msgstr "Giá cho thành viên là <strong>%s </strong>"
3240
+
3241
+ #: includes/functions.php:202 includes/functions.php:204 includes/functions.php:205
3242
+ #: includes/functions.php:206 includes/functions.php:209
3243
+ #, php-format
3244
+ msgid "<strong>%s</strong> now"
3245
+ msgstr "<strong>%s</strong>"
3246
+
3247
+ #: includes/functions.php:211 includes/functions.php:169 includes/functions.php:205
3248
+ #: includes/functions.php:213 includes/functions.php:214 includes/functions.php:215
3249
+ #: includes/functions.php:218
3250
+ #, php-format
3251
+ msgid " and then <strong>%s per %s for %d more %s</strong>."
3252
+ msgstr "và tiếp theo <strong>%s mỗi %s cho %d thêm %s</strong>."
3253
+
3254
+ #: includes/functions.php:215 includes/functions.php:173 includes/functions.php:209
3255
+ #: includes/functions.php:217 includes/functions.php:218 includes/functions.php:219
3256
+ #: includes/functions.php:222
3257
+ #, php-format
3258
+ msgid " and then <strong>%s every %d %s for %d more %s</strong>."
3259
+ msgstr "và tiếp theo <strong>%s mọi %d %s cho %d thêm %s</strong>,"
3260
+
3261
+ #: includes/functions.php:220 includes/functions.php:178 includes/functions.php:214
3262
+ #: includes/functions.php:222 includes/functions.php:223 includes/functions.php:224
3263
+ #: includes/functions.php:227
3264
+ #, php-format
3265
+ msgid " and then <strong>%s after %d %s</strong>."
3266
+ msgstr "và tiếp theo <strong>%s sau %d %s</strong>."
3267
+
3268
+ #: includes/functions.php:228 includes/functions.php:229 includes/functions.php:230
3269
+ #: includes/functions.php:231 includes/functions.php:235
3270
+ #, php-format
3271
+ msgid "The price for membership is <strong>%s per %s</strong>."
3272
+ msgstr "Giá cho thành viên là <strong>%s cho mỗi %s </strong>."
3273
+
3274
+ #: includes/functions.php:230 includes/functions.php:233 includes/functions.php:237
3275
+ #, php-format
3276
+ msgid "<strong>%s per %s</strong>."
3277
+ msgstr "<strong>%s cho mỗi %s</strong>."
3278
+
3279
+ #: includes/functions.php:235 includes/functions.php:233 includes/functions.php:234
3280
+ #: includes/functions.php:238 includes/functions.php:242
3281
+ #, php-format
3282
+ msgid "The price for membership is <strong>%s every %d %s</strong>."
3283
+ msgstr "Giá cho thành viên là <strong>%s mọin %d %s </strong>."
3284
+
3285
+ #: includes/functions.php:237 includes/functions.php:240 includes/functions.php:244
3286
+ #, php-format
3287
+ msgid "<strong>%s every %d %s</strong>."
3288
+ msgstr "<strong>%s mọi %d %s</strong>."
3289
+
3290
+ #: includes/functions.php:242 includes/functions.php:184 includes/functions.php:220
3291
+ #: includes/functions.php:228 includes/functions.php:238 includes/functions.php:239
3292
+ #: includes/functions.php:240 includes/functions.php:245 includes/functions.php:249
3293
+ #, php-format
3294
+ msgid " and then <strong>%s per %s</strong>."
3295
+ msgstr "và tiếp theo <strong>%s mỗi %s</strong>."
3296
+
3297
+ #: includes/functions.php:246 includes/functions.php:188 includes/functions.php:224
3298
+ #: includes/functions.php:232 includes/functions.php:242 includes/functions.php:243
3299
+ #: includes/functions.php:244 includes/functions.php:249 includes/functions.php:253
3300
+ #, php-format
3301
+ msgid " and then <strong>%s every %d %s</strong>."
3302
+ msgstr "và tiếp theo <strong>%s các %d %s</strong>."
3303
+
3304
+ #: includes/functions.php:264 includes/functions.php:202 includes/functions.php:238
3305
+ #: includes/functions.php:249 includes/functions.php:260 includes/functions.php:261
3306
+ #: includes/functions.php:262 includes/functions.php:267 includes/functions.php:271
3307
+ #: pages/levels.php:82
3308
+ msgid "After your initial payment, your first payment is Free."
3309
+ msgstr "Sau khi thanh toán ban đầu, thanh toán lần đầu của bạn là miễn phí."
3310
+
3311
+ #: includes/functions.php:268 includes/functions.php:206 includes/functions.php:242
3312
+ #: includes/functions.php:253 includes/functions.php:264 includes/functions.php:265
3313
+ #: includes/functions.php:266 includes/functions.php:271 includes/functions.php:275
3314
+ #: pages/levels.php:86
3315
+ #, php-format
3316
+ msgid "After your initial payment, your first %d payments are Free."
3317
+ msgstr "Sau khi thanh toán ban đầu, thanh toán lần đầu %d là miễn phí."
3318
+
3319
+ #: includes/functions.php:275 includes/functions.php:213 includes/functions.php:249
3320
+ #: includes/functions.php:260 includes/functions.php:271 includes/functions.php:272
3321
+ #: includes/functions.php:273 includes/functions.php:278 includes/functions.php:282
3322
+ #: pages/levels.php:93
3323
+ #, php-format
3324
+ msgid "After your initial payment, your first payment will cost %s."
3325
+ msgstr " Sau khi thanh toán ban đầu, thanh toán lần đầu là %s"
3326
+
3327
+ #: includes/functions.php:279 includes/functions.php:217 includes/functions.php:253
3328
+ #: includes/functions.php:264 includes/functions.php:275 includes/functions.php:276
3329
+ #: includes/functions.php:277 includes/functions.php:282 includes/functions.php:286
3330
+ #: pages/levels.php:97
3331
+ #, php-format
3332
+ msgid "After your initial payment, your first %d payments will cost %s."
3333
+ msgstr "Sau khi thanh toán ban đầu, thanh toán lần đầu của %d là %s"
3334
+
3335
+ #: includes/functions.php:290 includes/functions.php:228 includes/functions.php:264
3336
+ #: includes/functions.php:275 includes/functions.php:286 includes/functions.php:287
3337
+ #: includes/functions.php:288 includes/functions.php:293 includes/functions.php:297
3338
+ #, php-format
3339
+ msgid "Customers in %s will be charged %s%% tax."
3340
+ msgstr "Khách hang %s sẽ nộp %s%% thuế"
3341
+
3342
+ #: includes/functions.php:304 includes/functions.php:242 includes/functions.php:278
3343
+ #: includes/functions.php:289 includes/functions.php:300 includes/functions.php:301
3344
+ #: includes/functions.php:302 includes/functions.php:307 includes/functions.php:311
3345
+ #, php-format
3346
+ msgid "Membership expires after %d %s."
3347
+ msgstr "Quyền thành viên hết hạn sau %d %s."
3348
+
3349
+ #: includes/functions.php:615 includes/functions.php:491 includes/functions.php:514
3350
+ #: includes/functions.php:525 includes/functions.php:536 includes/functions.php:537
3351
+ #: includes/functions.php:538 includes/functions.php:545 includes/functions.php:569
3352
+ #: includes/functions.php:570 includes/functions.php:576 includes/functions.php:592
3353
+ msgid "User ID not found."
3354
+ msgstr "Mã thành viên không tìm thấy"
3355
+
3356
+ #: includes/functions.php:635 includes/functions.php:508 includes/functions.php:531
3357
+ #: includes/functions.php:542 includes/functions.php:553 includes/functions.php:554
3358
+ #: includes/functions.php:555 includes/functions.php:562 includes/functions.php:586
3359
+ #: includes/functions.php:587 includes/functions.php:589 includes/functions.php:596
3360
+ #: includes/functions.php:612
3361
+ msgid "Invalid level."
3362
+ msgstr "Kiểu thành viên không hợp lệ"
3363
+
3364
+ #: includes/functions.php:646 includes/functions.php:520 includes/functions.php:542
3365
+ #: includes/functions.php:553 includes/functions.php:564 includes/functions.php:565
3366
+ #: includes/functions.php:566 includes/functions.php:573 includes/functions.php:597
3367
+ #: includes/functions.php:598 includes/functions.php:600 includes/functions.php:607
3368
+ #: includes/functions.php:623
3369
+ msgid "not changing?"
3370
+ msgstr "không thay đổi?"
3371
+
3372
+ #: includes/functions.php:663 includes/functions.php:722 includes/functions.php:746
3373
+ #: includes/functions.php:537 includes/functions.php:559 includes/functions.php:570
3374
+ #: includes/functions.php:581 includes/functions.php:582 includes/functions.php:583
3375
+ #: includes/functions.php:590 includes/functions.php:592 includes/functions.php:605
3376
+ #: includes/functions.php:614 includes/functions.php:615 includes/functions.php:617
3377
+ #: includes/functions.php:624 includes/functions.php:626 includes/functions.php:628
3378
+ #: includes/functions.php:631 includes/functions.php:632 includes/functions.php:633
3379
+ #: includes/functions.php:637 includes/functions.php:640 includes/functions.php:649
3380
+ #: includes/functions.php:656 includes/functions.php:657 includes/functions.php:673
3381
+ #: includes/functions.php:674 includes/functions.php:676 includes/functions.php:683
3382
+ #: includes/functions.php:697 includes/functions.php:698 includes/functions.php:699
3383
+ #: includes/functions.php:700 includes/functions.php:707 includes/functions.php:723
3384
+ msgid "Error interacting with database"
3385
+ msgstr "Lỗi tương tác với cơ sở dữ liệu"
3386
+
3387
+ #: includes/functions.php:787 includes/functions.php:826 includes/functions.php:629
3388
+ #: includes/functions.php:651 includes/functions.php:667 includes/functions.php:668
3389
+ #: includes/functions.php:678 includes/functions.php:681 includes/functions.php:690
3390
+ #: includes/functions.php:697 includes/functions.php:698 includes/functions.php:706
3391
+ #: includes/functions.php:714 includes/functions.php:717 includes/functions.php:720
3392
+ #: includes/functions.php:736 includes/functions.php:737 includes/functions.php:738
3393
+ #: includes/functions.php:739 includes/functions.php:741 includes/functions.php:748
3394
+ #: includes/functions.php:753 includes/functions.php:764 includes/functions.php:777
3395
+ #: includes/functions.php:778 includes/functions.php:780 includes/functions.php:803
3396
+ msgid "Membership level not found."
3397
+ msgstr "Kiểu thành viên không có"
3398
+
3399
+ #: includes/functions.php:1196 includes/functions.php:1100 includes/functions.php:1101
3400
+ #: includes/functions.php:1118 includes/functions.php:1142 includes/functions.php:1143
3401
+ #: includes/functions.php:1150 includes/functions.php:1157 includes/functions.php:1173
3402
+ msgid "No code was given to check."
3403
+ msgstr "Không có mã đã được đưa ra để kiểm tra."
3404
+
3405
+ #: includes/functions.php:1205 includes/functions.php:1050 includes/functions.php:1072
3406
+ #: includes/functions.php:1088 includes/functions.php:1099 includes/functions.php:1102
3407
+ #: includes/functions.php:1109 includes/functions.php:1110 includes/functions.php:1112
3408
+ #: includes/functions.php:1113 includes/functions.php:1127 includes/functions.php:1151
3409
+ #: includes/functions.php:1152 includes/functions.php:1159 includes/functions.php:1166
3410
+ #: includes/functions.php:1182
3411
+ msgid "The discount code could not be found."
3412
+ msgstr "Mã giảm giá không có hoặc hết hạn."
3413
+
3414
+ #: includes/functions.php:1220 includes/functions.php:1066 includes/functions.php:1088
3415
+ #: includes/functions.php:1104 includes/functions.php:1115 includes/functions.php:1118
3416
+ #: includes/functions.php:1124 includes/functions.php:1125 includes/functions.php:1128
3417
+ #: includes/functions.php:1129 includes/functions.php:1142 includes/functions.php:1166
3418
+ #: includes/functions.php:1167 includes/functions.php:1174 includes/functions.php:1181
3419
+ #: includes/functions.php:1197
3420
+ #, php-format
3421
+ msgid "This discount code goes into effect on %s."
3422
+ msgstr "Mã giảm giá này sẽ có hiệu lực đến %s."
3423
+
3424
+ #: includes/functions.php:1227 includes/functions.php:1075 includes/functions.php:1097
3425
+ #: includes/functions.php:1113 includes/functions.php:1124 includes/functions.php:1127
3426
+ #: includes/functions.php:1131 includes/functions.php:1132 includes/functions.php:1137
3427
+ #: includes/functions.php:1138 includes/functions.php:1149 includes/functions.php:1173
3428
+ #: includes/functions.php:1174 includes/functions.php:1181 includes/functions.php:1188
3429
+ #: includes/functions.php:1204
3430
+ #, php-format
3431
+ msgid "This discount code expired on %s."
3432
+ msgstr "Mã giảm giá này sẽ hết hiệu lực vào %s."
3433
+
3434
+ #: includes/functions.php:1237 includes/functions.php:1087 includes/functions.php:1109
3435
+ #: includes/functions.php:1125 includes/functions.php:1136 includes/functions.php:1139
3436
+ #: includes/functions.php:1141 includes/functions.php:1142 includes/functions.php:1149
3437
+ #: includes/functions.php:1150 includes/functions.php:1159 includes/functions.php:1183
3438
+ #: includes/functions.php:1184 includes/functions.php:1191 includes/functions.php:1198
3439
+ #: includes/functions.php:1214
3440
+ msgid "This discount code is no longer valid."
3441
+ msgstr "Mã giảm giá này đã hết hạn"
3442
+
3443
+ #: includes/functions.php:1250 includes/functions.php:1102 includes/functions.php:1124
3444
+ #: includes/functions.php:1140 includes/functions.php:1151 includes/functions.php:1154
3445
+ #: includes/functions.php:1155 includes/functions.php:1164 includes/functions.php:1165
3446
+ #: includes/functions.php:1172 includes/functions.php:1196 includes/functions.php:1197
3447
+ #: includes/functions.php:1204 includes/functions.php:1211 includes/functions.php:1227
3448
+ msgid "This discount code does not apply to this membership level."
3449
+ msgstr "9Mã giảm giá này không áp dung cho kiểu thành viên này"
3450
+
3451
+ #: includes/functions.php:1276 includes/functions.php:1110 includes/functions.php:1132
3452
+ #: includes/functions.php:1148 includes/functions.php:1159 includes/functions.php:1162
3453
+ #: includes/functions.php:1172 includes/functions.php:1180 includes/functions.php:1181
3454
+ #: includes/functions.php:1182 includes/functions.php:1198 includes/functions.php:1222
3455
+ #: includes/functions.php:1223 includes/functions.php:1230 includes/functions.php:1237
3456
+ #: includes/functions.php:1253
3457
+ msgid "This discount code is okay."
3458
+ msgstr "Mã giảm giá này có hiệu lực"
3459
+
3460
+ #: includes/functions.php:1301 includes/functions.php:1134 includes/functions.php:1156
3461
+ #: includes/functions.php:1172 includes/functions.php:1183 includes/functions.php:1186
3462
+ #: includes/functions.php:1196 includes/functions.php:1205 includes/functions.php:1206
3463
+ #: includes/functions.php:1223 includes/functions.php:1247 includes/functions.php:1248
3464
+ #: includes/functions.php:1255 includes/functions.php:1262 includes/functions.php:1278
3465
+ msgid "and"
3466
+ msgstr "và"
3467
+
3468
+ #: includes/functions.php:1496 includes/functions.php:1319 includes/functions.php:1341
3469
+ #: includes/functions.php:1361 includes/functions.php:1372 includes/functions.php:1375
3470
+ #: includes/functions.php:1385 includes/functions.php:1394 includes/functions.php:1395
3471
+ #: includes/functions.php:1412 includes/functions.php:1436 includes/functions.php:1437
3472
+ #: includes/functions.php:1450 includes/functions.php:1457 includes/functions.php:1473
3473
+ msgid "Sign Up for !!name!! Now"
3474
+ msgstr "Đăng ký ngay cho !!name!!"
3475
+
3476
+ #: includes/functions.php:1502 includes/functions.php:1325 includes/functions.php:1347
3477
+ #: includes/functions.php:1367 includes/functions.php:1378 includes/functions.php:1381
3478
+ #: includes/functions.php:1391 includes/functions.php:1400 includes/functions.php:1401
3479
+ #: includes/functions.php:1418 includes/functions.php:1442 includes/functions.php:1443
3480
+ #: includes/functions.php:1456 includes/functions.php:1463 includes/functions.php:1479
3481
+ msgid "Please specify a level id."
3482
+ msgstr "Hay chỉ rõ kiểu thành viên7"
3483
+
3484
+ #: includes/init.php:237 includes/profile.php:39 includes/init.php:229
3485
+ #: includes/init.php:232 includes/init.php:233 includes/init.php:235
3486
+ #: includes/profile.php:37
3487
+ msgid "None"
3488
+ msgstr "Không"
3489
+
3490
+ #: includes/license.php:51
3491
+ msgid "Your license key has been validated."
3492
+ msgstr ""
3493
+
3494
+ #: includes/license.php:81
3495
+ msgid "Paid Memberships Pro Support License"
3496
+ msgstr ""
3497
+
3498
+ #: includes/license.php:86
3499
+ msgid "License Key"
3500
+ msgstr ""
3501
+
3502
+ #: includes/license.php:89
3503
+ msgid ""
3504
+ "Enter your support license key.</strong> Your license key can be found in your "
3505
+ "membership email receipt or in your <a href=\"http://www.paidmembershipspro.com/"
3506
+ "login/?redirect_to=/membership-account/\" target=\"_blank\">Membership Account</a>."
3507
+ msgstr ""
3508
+
3509
+ #: includes/license.php:91
3510
+ msgid ""
3511
+ "Visit the PMPro <a href=\"http://www.paidmembershipspro.com/login/?redirect_to=/"
3512
+ "membership-account/\" target=\"_blank\">Membership Account</a> page to confirm that "
3513
+ "your account is active and to find your license key."
3514
+ msgstr ""
3515
+
3516
+ #: includes/license.php:91
3517
+ msgid "Your license is invalid or expired."
3518
+ msgstr ""
3519
+
3520
+ #: includes/license.php:93
3521
+ #, php-format
3522
+ msgid ""
3523
+ "<p><strong>Thank you!</strong> A valid <strong>%s</strong> license key has been used "
3524
+ "to activate your support license on this site.</p>"
3525
+ msgstr ""
3526
+
3527
+ #: includes/license.php:100
3528
+ msgid "Enter license key here..."
3529
+ msgstr ""
3530
+
3531
+ #: includes/license.php:102
3532
+ msgid "Verify Key"
3533
+ msgstr ""
3534
+
3535
+ #: includes/license.php:273
3536
+ msgid ""
3537
+ "If you're running Paid Memberships Pro on a production website, we recommend an "
3538
+ "annual support license."
3539
+ msgstr ""
3540
+
3541
+ #: includes/license.php:273
3542
+ msgid "Invalid PMPro License Key."
3543
+ msgstr ""
3544
+
3545
+ #: includes/license.php:274
3546
+ msgid "Dismiss"
3547
+ msgstr "Bỏ qua"
3548
+
3549
+ #: includes/license.php:274
3550
+ msgid "More Info"
3551
+ msgstr "Thêm thông tin"
3552
+
3553
+ #: includes/localization.php:26 includes/localization.php:23
3554
+ msgid "Day"
3555
+ msgstr "Ngày"
3556
+
3557
+ #: includes/localization.php:28 includes/localization.php:25
3558
+ msgid "Week"
3559
+ msgstr "Tuần"
3560
+
3561
+ #: includes/localization.php:30 includes/localization.php:27
3562
+ msgid "Month"
3563
+ msgstr "Tháng"
3564
+
3565
+ #: includes/localization.php:32 includes/localization.php:29
3566
+ msgid "Year"
3567
+ msgstr "Năm"
3568
+
3569
+ #: includes/localization.php:37
3570
+ msgid "Days"
3571
+ msgstr "Ngày"
3572
+
3573
+ #: includes/localization.php:39
3574
+ msgid "Weeks"
3575
+ msgstr "Tuần"
3576
+
3577
+ #: includes/localization.php:41
3578
+ msgid "Months"
3579
+ msgstr "Tháng"
3580
+
3581
+ #: includes/localization.php:43
3582
+ msgid "Years"
3583
+ msgstr "Năm"
3584
+
3585
+ #: includes/metaboxes.php:38
3586
+ msgid ""
3587
+ "This post is already protected for this level because it is within a category that "
3588
+ "requires membership."
3589
+ msgstr ""
3590
+ "Bài này đã được bảo vệ vì nó nằm trong thể loại đòi hỏi quyền thành viên truy cập8."
3591
+
3592
+ #: includes/metaboxes.php:99 includes/metaboxes.php:100
3593
+ msgid "Require Membership"
3594
+ msgstr "Đòi hỏi quyền thành viên"
3595
+
3596
+ #: includes/profile.php:36 includes/profile.php:34
3597
+ msgid "Current Level"
3598
+ msgstr "Kiểu Thành Viên Hiện Tại"
3599
+
3600
+ #: includes/profile.php:60 includes/profile.php:54
3601
+ msgid "Not paying."
3602
+ msgstr "Chưa trả phí."
3603
+
3604
+ #: includes/profile.php:68 includes/profile.php:64
3605
+ msgid ""
3606
+ "This will not change the subscription at the gateway unless the 'Cancel' checkbox is "
3607
+ "selected below."
3608
+ msgstr ""
3609
+ "Điều này sẽ không thay đổi đăng ký tại các cổng, trừ khi các hộp kiểm 'Hủy bỏ' được "
3610
+ "chọn dưới đây."
3611
+
3612
+ #: includes/upgradecheck.php:422 includes/upgradecheck.php:401
3613
+ #: includes/upgradecheck.php:410
3614
+ #, php-format
3615
+ msgid "This content is for !!levels!! members only.<br /><a href=\"%s\">Register</a>"
3616
+ msgstr "Nội dung này là dành cho các thành viên,<br /><a href=\"%s\">Đăng ký</a>"
3617
+
3618
+ #: includes/upgradecheck.php:425 includes/upgradecheck.php:404
3619
+ #: includes/upgradecheck.php:413
3620
+ #, php-format
3621
+ msgid ""
3622
+ "This content is for !!levels!! members only.<br /><a href=\"%s\">Log In</a> <a href="
3623
+ "\"%s\">Register</a>"
3624
+ msgstr ""
3625
+ "Nội dung này là dành cho các thành viên !!levels!!.<br /><a href=\"%s\">Đăng nhập</a> "
3626
+ "<a href=\"%s\">Đăng ký</a>"
3627
+
3628
+ #: includes/upgradecheck.php:429 includes/upgradecheck.php:408
3629
+ #: includes/upgradecheck.php:417
3630
+ msgid ""
3631
+ "This content is for !!levels!! members only. Visit the site and log in/register to "
3632
+ "read."
3633
+ msgstr ""
3634
+ "Nội dung này là dành cho các thành viên !!levels!!. Truy cập và đăng nhập/đăng ký để "
3635
+ "tải"
3636
+
3637
+ #: pages/billing.php:23 pages/billing.php:14
3638
+ #, php-format
3639
+ msgid "Logged in as <strong>%s</strong>."
3640
+ msgstr "Đã đăng nhập là <strong>%s</strong>.b"
3641
+
3642
+ #: pages/billing.php:23 pages/billing.php:14
3643
+ msgid "logout"
3644
+ msgstr "đăng xuất"
3645
+
3646
+ #: pages/billing.php:25 pages/cancel.php:52 pages/invoice.php:109 pages/levels.php:13
3647
+ #: shortcodes/pmpro_account.php:44 shortcodes/pmpro_account.php:123 pages/account.php:12
3648
+ #: pages/account.php:18 pages/account.php:92 pages/billing.php:16
3649
+ msgid "Level"
3650
+ msgstr "Kiểu/Cấp độ"
3651
+
3652
+ #: pages/billing.php:27 pages/account.php:14 pages/billing.php:18
3653
+ msgid "Membership Fee"
3654
+ msgstr "Phí thành viên"
3655
+
3656
+ #: pages/billing.php:31 pages/account.php:18 pages/billing.php:22 pages/levels.php:70
3657
+ #, php-format
3658
+ msgid "%s every %d %s."
3659
+ msgstr "%s mọi %d %s."
3660
+
3661
+ #: pages/billing.php:33 pages/account.php:20 pages/billing.php:24 pages/levels.php:66
3662
+ #, php-format
3663
+ msgid "%s per %s."
3664
+ msgstr "%s mỗi %s."
3665
+
3666
+ #: pages/billing.php:42 pages/account.php:25 pages/account.php:29 pages/billing.php:29
3667
+ #: pages/billing.php:33
3668
+ msgid "Duration"
3669
+ msgstr "Thời gian"
3670
+
3671
+ #: pages/billing.php:52 pages/billing.php:39 pages/billing.php:43
3672
+ msgid ""
3673
+ "Your payment subscription is managed by PayPal. Please <a href=\"http://www.paypal.com"
3674
+ "\">login to PayPal here</a> to update your billing information."
3675
+ msgstr ""
3676
+ "Đăng ký thanh toán của bạn được quản lý bằng PayPal. Hãy <a href=\"http://www.paypal."
3677
+ "com\"> đăng nhập vào PayPal tại đây </a> để cập nhật thông tin thanh toán của bạn."
3678
+
3679
+ #: pages/billing.php:78 pages/checkout.php:318 pages/billing.php:65 pages/billing.php:69
3680
+ #: pages/checkout.php:305 pages/checkout.php:307 pages/checkout.php:309
3681
+ #: pages/checkout.php:321 pages/checkout.php:328
3682
+ msgid "First Name"
3683
+ msgstr "Tên"
3684
+
3685
+ #: pages/billing.php:82 pages/checkout.php:322 pages/billing.php:69 pages/billing.php:73
3686
+ #: pages/checkout.php:309 pages/checkout.php:311 pages/checkout.php:313
3687
+ #: pages/checkout.php:325 pages/checkout.php:332
3688
+ msgid "Last Name"
3689
+ msgstr "Họ"
3690
+
3691
+ #: pages/billing.php:86 pages/checkout.php:326 pages/billing.php:73 pages/billing.php:77
3692
+ #: pages/checkout.php:313 pages/checkout.php:315 pages/checkout.php:317
3693
+ #: pages/checkout.php:329 pages/checkout.php:336
3694
+ msgid "Address 1"
3695
+ msgstr "Địa chỉ 1"
3696
+
3697
+ #: pages/billing.php:90 pages/checkout.php:330 pages/billing.php:77 pages/billing.php:81
3698
+ #: pages/checkout.php:317 pages/checkout.php:319 pages/checkout.php:321
3699
+ #: pages/checkout.php:333 pages/checkout.php:340
3700
+ msgid "Address 2"
3701
+ msgstr "Địa chỉ 2"
3702
+
3703
+ #: pages/billing.php:100 pages/checkout.php:340 pages/billing.php:87
3704
+ #: pages/billing.php:91 pages/checkout.php:327 pages/checkout.php:329
3705
+ #: pages/checkout.php:331 pages/checkout.php:343 pages/checkout.php:350
3706
+ msgid "City"
3707
+ msgstr "Thành phố"
3708
+
3709
+ #: pages/billing.php:104 pages/checkout.php:344 pages/billing.php:91
3710
+ #: pages/billing.php:95 pages/checkout.php:331 pages/checkout.php:333
3711
+ #: pages/checkout.php:335 pages/checkout.php:347 pages/checkout.php:354
3712
+ msgid "State"
3713
+ msgstr "Quận"
3714
+
3715
+ #: pages/billing.php:108 pages/checkout.php:348 pages/billing.php:95
3716
+ #: pages/billing.php:99 pages/checkout.php:335 pages/checkout.php:337
3717
+ #: pages/checkout.php:339 pages/checkout.php:351 pages/checkout.php:358
3718
+ msgid "Postal Code"
3719
+ msgstr "Mã vùng"
3720
+
3721
+ #: pages/billing.php:117 pages/checkout.php:357 pages/billing.php:104
3722
+ #: pages/billing.php:108 pages/checkout.php:344 pages/checkout.php:346
3723
+ #: pages/checkout.php:348 pages/checkout.php:360 pages/checkout.php:367
3724
+ msgid "City, State Zip"
3725
+ msgstr "Bang Hạt"
3726
+
3727
+ #: pages/billing.php:170 pages/checkout.php:410 pages/billing.php:157
3728
+ #: pages/billing.php:161 pages/checkout.php:397 pages/checkout.php:399
3729
+ #: pages/checkout.php:401 pages/checkout.php:413 pages/checkout.php:420
3730
+ msgid "Country"
3731
+ msgstr "Quốc gia"
3732
+
3733
+ #: pages/billing.php:195 pages/checkout.php:435 pages/billing.php:182
3734
+ #: pages/billing.php:186 pages/checkout.php:422 pages/checkout.php:424
3735
+ #: pages/checkout.php:426 pages/checkout.php:438 pages/checkout.php:445
3736
+ msgid "Phone"
3737
+ msgstr "Số điện thoại"
3738
+
3739
+ #: pages/billing.php:206 pages/checkout.php:216 pages/checkout.php:449
3740
+ #: pages/billing.php:193 pages/billing.php:197 pages/checkout.php:204
3741
+ #: pages/checkout.php:207 pages/checkout.php:209 pages/checkout.php:436
3742
+ #: pages/checkout.php:438 pages/checkout.php:440 pages/checkout.php:453
3743
+ #: pages/checkout.php:460
3744
+ msgid "E-mail Address"
3745
+ msgstr "Địa chỉ Email"
3746
+
3747
+ #: pages/billing.php:210 pages/checkout.php:458 pages/billing.php:197
3748
+ #: pages/billing.php:201 pages/checkout.php:445 pages/checkout.php:447
3749
+ #: pages/checkout.php:449 pages/checkout.php:462 pages/checkout.php:469
3750
+ msgid "Confirm E-mail"
3751
+ msgstr "Xác nhận E-mail"
3752
+
3753
+ #: pages/billing.php:230 pages/billing.php:217 pages/billing.php:221
3754
+ msgid "Credit Card Information"
3755
+ msgstr "Thông tin thẻ tín dụng"
3756
+
3757
+ #: pages/billing.php:230 pages/billing.php:217 pages/billing.php:221
3758
+ #, php-format
3759
+ msgid "We accept %s"
3760
+ msgstr "Chúng tôi chap nhận %s"
3761
+
3762
+ #: pages/billing.php:353 pages/billing.php:309 pages/billing.php:313
3763
+ #: pages/billing.php:344
3764
+ msgid ""
3765
+ "This subscription is not recurring. So you don't need to update your billing "
3766
+ "information."
3767
+ msgstr ""
3768
+ "Đăng ký này không định kỳ. Vì vậy, bạn không cần phải cập nhật thông tin thanh toán "
3769
+ "của bạn."
3770
+
3771
+ #: pages/cancel.php:26 pages/cancel.php:14
3772
+ msgid "Are you sure you want to cancel your membership?"
3773
+ msgstr "Bạn có chắc chắn muốn hủy bỏ quyền thành viên của bạn?"
3774
+
3775
+ #: pages/cancel.php:32
3776
+ #, php-format
3777
+ msgid "Are you sure you want to cancel your %s membership?"
3778
+ msgstr "Bạn có chắc chắn muốn hủy bỏ quyền thành viên %s của bạn?"
3779
+
3780
+ #: pages/cancel.php:37 pages/cancel.php:17
3781
+ msgid "Yes, cancel my account"
3782
+ msgstr "Có, hủy bỏ tài khoản của tôi"
3783
+
3784
+ #: pages/cancel.php:38 pages/cancel.php:19
3785
+ msgid "No, keep my account"
3786
+ msgstr "Không, giữ lại tài khoản của tôi"
3787
+
3788
+ #: pages/cancel.php:48 shortcodes/pmpro_account.php:40 pages/account.php:14
3789
+ msgid "My Memberships"
3790
+ msgstr "Quyền Thành Viên Của Tôi"
3791
+
3792
+ #: pages/cancel.php:77
3793
+ msgid "Cancel All Memberships"
3794
+ msgstr "Hủy Bỏ Các Quyền Thành Viên"
3795
+
3796
+ #: pages/cancel.php:86 pages/cancel.php:22
3797
+ msgid "Click here to go to the home page."
3798
+ msgstr "Nhấn vào đây để tới trang chủ."
3799
+
3800
+ #: pages/checkout.php:35 pages/checkout.php:26 pages/checkout.php:27
3801
+ #: pages/checkout.php:28
3802
+ msgid ""
3803
+ "Almost done. Review the membership information and pricing below then <strong>click "
3804
+ "the \"Complete Payment\" button</strong> to finish your order."
3805
+ msgstr ""
3806
+ "Sắp xong. Xem lại các thông tin thành viên và giá cả dưới đây sau đó <strong> nhấn "
3807
+ "vào nút \"Hoàn thành thanh toán\" </ strong> để hoàn tất đơn đặt hàng của bạn."
3808
+
3809
+ #: pages/checkout.php:42 pages/checkout.php:33 pages/checkout.php:34
3810
+ #: pages/checkout.php:35
3811
+ msgid "change"
3812
+ msgstr "thay đổi"
3813
+
3814
+ #: pages/checkout.php:50 pages/checkout.php:41 pages/checkout.php:42
3815
+ #: pages/checkout.php:43
3816
+ #, php-format
3817
+ msgid "You have selected the <strong>%s</strong> membership level."
3818
+ msgstr "Bạn đã chọn kiểu thành viên là <strong>%s</strong>"
3819
+
3820
+ #: pages/checkout.php:60 pages/checkout.php:51 pages/checkout.php:53
3821
+ #, php-format
3822
+ msgid ""
3823
+ "<p class=\"pmpro_level_discount_applied\">The <strong>%s</strong> code has been "
3824
+ "applied to your order.</p>"
3825
+ msgstr ""
3826
+ "<p class=\"pmpro_level_discount_applied\">Mã <strong>%s</strong> đã đượcáp dung cho "
3827
+ "đơn hang của bạn.</p>"
3828
+
3829
+ #: pages/checkout.php:71 services/applydiscountcode.php:89 pages/checkout.php:62
3830
+ #: pages/checkout.php:63 pages/checkout.php:64 services/applydiscountcode.php:74
3831
+ #: services/applydiscountcode.php:75 services/applydiscountcode.php:78
3832
+ msgid "Click here to change your discount code"
3833
+ msgstr "Nhấn vào đây để thay đổi mã giảm giá của bạn"
3834
+
3835
+ #: pages/checkout.php:73 pages/checkout.php:64 pages/checkout.php:65
3836
+ #: pages/checkout.php:66
3837
+ msgid "Click here to enter your discount code"
3838
+ msgstr "Nhấn vào đây để nhập mã giảm giá của bạn"
3839
+
3840
+ #: pages/checkout.php:73 pages/checkout.php:64 pages/checkout.php:65
3841
+ #: pages/checkout.php:66
3842
+ msgid "Do you have a discount code?"
3843
+ msgstr "Bạn có một mã giảm giá không?"
3844
+
3845
+ #: pages/checkout.php:172 pages/checkout.php:160 pages/checkout.php:163
3846
+ #: pages/checkout.php:165
3847
+ msgid "Account Information"
3848
+ msgstr "Thông tin tài khoản"
3849
+
3850
+ #: pages/checkout.php:172 pages/checkout.php:160 pages/checkout.php:163
3851
+ #: pages/checkout.php:165
3852
+ msgid "Already have an account?"
3853
+ msgstr "Bạn đã có tài khoản?"
3854
+
3855
+ #: pages/checkout.php:172 pages/checkout.php:160 pages/checkout.php:163
3856
+ #: pages/checkout.php:165
3857
+ msgid "Log in here"
3858
+ msgstr "Đăng nhập ở đây"
3859
+
3860
+ #: pages/checkout.php:198 pages/checkout.php:186 pages/checkout.php:189
3861
+ #: pages/checkout.php:191
3862
+ msgid "Confirm Password"
3863
+ msgstr "Xác nhận mật khẩu"
3864
+
3865
+ #: pages/checkout.php:225 pages/checkout.php:213 pages/checkout.php:216
3866
+ #: pages/checkout.php:218
3867
+ msgid "Confirm E-mail Address"
3868
+ msgstr "Xác nhận địa chỉ E-mail"
3869
+
3870
+ #: pages/checkout.php:244 pages/checkout.php:232 pages/checkout.php:235
3871
+ #: pages/checkout.php:237
3872
+ msgid "Full Name"
3873
+ msgstr "Họ tên"
3874
+
3875
+ #: pages/checkout.php:245 pages/checkout.php:233 pages/checkout.php:236
3876
+ #: pages/checkout.php:238
3877
+ msgid "LEAVE THIS BLANK"
3878
+ msgstr "ĐỂ TRỐNG"
3879
+
3880
+ #: pages/checkout.php:269 pages/checkout.php:257 pages/checkout.php:260
3881
+ #: pages/checkout.php:262
3882
+ #, php-format
3883
+ msgid ""
3884
+ "You are logged in as <strong>%s</strong>. If you would like to use a different "
3885
+ "account for this membership, <a href=\"%s\">log out now</a>."
3886
+ msgstr ""
3887
+ "Bạn đã đăng nhập là d<strong>%s</strong>.Nếu bạn muốn sử dụng tài khoản khác cho "
3888
+ "thành viên này, <a href=\"%s\">Đăng xuất ngay</a>."
3889
+
3890
+ #: pages/checkout.php:285 pages/checkout.php:276 pages/checkout.php:278
3891
+ #: pages/checkout.php:292 pages/checkout.php:299
3892
+ msgid "Choose your Payment Method"
3893
+ msgstr "Chọn cách thanh toán của bạn"
3894
+
3895
+ #: pages/checkout.php:293 pages/checkout.php:284 pages/checkout.php:286
3896
+ #: pages/checkout.php:300 pages/checkout.php:307
3897
+ msgid "Check Out with a Credit Card Here"
3898
+ msgstr "Thanh toán với Thẻ tín dung ở đây"
3899
+
3900
+ #: pages/checkout.php:681 pages/checkout.php:277 pages/checkout.php:284
3901
+ #: pages/checkout.php:657 pages/checkout.php:672 pages/checkout.php:673
3902
+ #, php-format
3903
+ msgid "I agree to the %s"
3904
+ msgstr "Tôi đồng ý với %s"
3905
+
3906
+ #: pages/checkout.php:701 pages/checkout.php:667 pages/checkout.php:674
3907
+ #: pages/checkout.php:677 pages/checkout.php:692 pages/checkout.php:693
3908
+ msgid "Complete Payment"
3909
+ msgstr "Hoàn thành thanh toán"
3910
+
3911
+ #: pages/checkout.php:723 pages/checkout.php:687 pages/checkout.php:694
3912
+ #: pages/checkout.php:697 pages/checkout.php:713 pages/checkout.php:714
3913
+ msgid "Processing..."
3914
+ msgstr "Đang xử lý..."
3915
+
3916
+ #: pages/confirmation.php:12
3917
+ msgid "Your payment has been submitted. Your membership will be activated shortly."
3918
+ msgstr ""
3919
+ "Thanh toán của bạn đã được gửi đi. Quyền thành viên của bạn sẽ được kích hoạt ngay"
3920
+
3921
+ #: pages/confirmation.php:14
3922
+ #, php-format
3923
+ msgid "Thank you for your membership to %s. Your %s membership is now active."
3924
+ msgstr ""
3925
+ "Cám ơn bạn đã đang ký thanh viên của %s. Tài khoản thành viên %s sẽ được kích hoạt "
3926
+ "ngay"
3927
+
3928
+ #: pages/confirmation.php:28
3929
+ #, php-format
3930
+ msgid ""
3931
+ "Below are details about your membership account and a receipt for your initial "
3932
+ "membership invoice. A welcome email with a copy of your initial membership invoice "
3933
+ "has been sent to %s."
3934
+ msgstr ""
3935
+ "Dưới đây là chi tiết về tài khoản thành viên của bạn và nhận được một hóa đơn cho "
3936
+ "thanh toán thành viên lần đầu của bạn. Một email chào đón với một bản sao của hóa đơn "
3937
+ "thành viên lần đầu của bạn đã được gửi đến %s."
3938
+
3939
+ #: pages/confirmation.php:41 pages/invoice.php:22
3940
+ #, php-format
3941
+ msgid "Invoice #%s on %s"
3942
+ msgstr "Hóa đơn số#%s trên %s"
3943
+
3944
+ #: pages/confirmation.php:43 pages/invoice.php:24
3945
+ msgid "Print"
3946
+ msgstr "In ấn"
3947
+
3948
+ #: pages/confirmation.php:46 pages/confirmation.php:104 pages/invoice.php:27
3949
+ #: pages/confirmation.php:45 pages/confirmation.php:102 pages/invoice.php:26
3950
+ msgid "Account"
3951
+ msgstr "Tài khoản"
3952
+
3953
+ #: pages/confirmation.php:49 pages/invoice.php:30 pages/account.php:29
3954
+ #: pages/account.php:33 pages/confirmation.php:48 pages/invoice.php:29
3955
+ msgid "Membership Expires"
3956
+ msgstr "Hết hạn"
3957
+
3958
+ #: pages/confirmation.php:63 pages/invoice.php:50 pages/account.php:105
3959
+ #: pages/account.php:109 pages/confirmation.php:61 pages/invoice.php:48
3960
+ msgid "Payment Method"
3961
+ msgstr "Phương thức thanh toán "
3962
+
3963
+ #: pages/confirmation.php:65 pages/invoice.php:52 pages/invoice.php:110
3964
+ #: pages/confirmation.php:63 pages/invoice.php:50 pages/invoice.php:107
3965
+ #: pages/invoice.php:109
3966
+ msgid "Total Billed"
3967
+ msgstr "Tổng thanh toán "
3968
+
3969
+ #: pages/confirmation.php:82 pages/invoice.php:69 pages/confirmation.php:80
3970
+ #: pages/invoice.php:67
3971
+ msgid "ending in"
3972
+ msgstr "kết thúc ở"
3973
+
3974
+ #: pages/confirmation.php:97
3975
+ #, php-format
3976
+ msgid ""
3977
+ "Below are details about your membership account. A welcome email has been sent to %s."
3978
+ msgstr ""
3979
+ "Dưới đây là chi tiết về tài khoản thành viên của bạn. Một email chào mừng đã được gửi "
3980
+ "đến %s."
3981
+
3982
+ #: pages/confirmation.php:105 pages/confirmation.php:103
3983
+ msgid "Pending"
3984
+ msgstr "Đang xử lý"
3985
+
3986
+ #: pages/confirmation.php:113 pages/invoice.php:141 pages/confirmation.php:111
3987
+ #: pages/invoice.php:139
3988
+ msgid "View Your Membership Account &rarr;"
3989
+ msgstr "Xem thông tin thành viên của bạn &rarr;"
3990
+
3991
+ #: pages/confirmation.php:115 pages/confirmation.php:113
3992
+ msgid ""
3993
+ "If your account is not activated within a few minutes, please contact the site owner."
3994
+ msgstr ""
3995
+ "Nếu tài khoản của bạn chưa được kích hoạt trong vòng một vài phút, hãy liên hệ với "
3996
+ "chủ sở hữu trang web."
3997
+
3998
+ #: pages/invoice.php:79 pages/invoice.php:77
3999
+ msgid "Subtotal"
4000
+ msgstr "Tổng phụ"
4001
+
4002
+ #: pages/invoice.php:82 pages/invoice.php:80
4003
+ msgid "Coupon"
4004
+ msgstr "Mã khuyến mại"
4005
+
4006
+ #: pages/invoice.php:108 pages/invoice.php:106
4007
+ msgid "Invoice #"
4008
+ msgstr "Hóa đơn số"
4009
+
4010
+ #: pages/invoice.php:134 pages/invoice.php:132
4011
+ msgid "No invoices found."
4012
+ msgstr "Không có hóa đơn "
4013
+
4014
+ #: pages/invoice.php:145 pages/invoice.php:143
4015
+ msgid "&larr; View All Invoices"
4016
+ msgstr "&larr; Xem các hóa đơn"
4017
+
4018
+ #: pages/levels.php:14
4019
+ msgid "Price"
4020
+ msgstr "Giá"
4021
+
4022
+ #: pages/levels.php:33 pages/levels.php:43
4023
+ msgid "Free"
4024
+ msgstr "Miễn phí"
4025
+
4026
+ #: pages/levels.php:47 pages/levels.php:49 pages/levels.php:113 pages/levels.php:115
4027
+ msgid "Select"
4028
+ msgstr "Chọn"
4029
+
4030
+ #: pages/levels.php:57 shortcodes/pmpro_account.php:59 pages/account.php:33
4031
+ #: pages/levels.php:123
4032
+ msgid "Renew"
4033
+ msgstr "Thiết lập lại"
4034
+
4035
+ #: pages/levels.php:63 pages/levels.php:117 pages/levels.php:129
4036
+ msgid "Your&nbsp;Level"
4037
+ msgstr "Loại tài khoản của bạn"
4038
+
4039
+ #: pages/levels.php:79 pages/levels.php:129 pages/levels.php:145
4040
+ msgid "&larr; Return to Your Account"
4041
+ msgstr "&larr; Quay về Tài khoản của bạn"
4042
+
4043
+ #: pages/levels.php:81 pages/levels.php:131 pages/levels.php:147
4044
+ msgid "&larr; Return to Home"
4045
+ msgstr "&larr; Trở lại trang chủ"
4046
+
4047
+ #: paid-memberships-pro.php:123 adminpages/orders.php:398 adminpages/orders.php:448
4048
+ #: paid-memberships-pro.php:115 paid-memberships-pro.php:116
4049
+ msgid "Testing Only"
4050
+ msgstr "Thủ nghiệm"
4051
+
4052
+ #: paid-memberships-pro.php:128 paid-memberships-pro.php:120
4053
+ #: paid-memberships-pro.php:121
4054
+ msgid "PayPal Payflow Pro/PayPal Pro"
4055
+ msgstr ""
4056
+
4057
+ #: paid-memberships-pro.php:133 paid-memberships-pro.php:125
4058
+ #: paid-memberships-pro.php:126
4059
+ msgid "Cybersource"
4060
+ msgstr ""
4061
+
4062
+ #: preheaders/account.php:10 preheaders/levels.php:22 preheaders/account.php:7
4063
+ #: preheaders/account.php:9 preheaders/levels.php:19 preheaders/levels.php:21
4064
+ msgid "Your membership status has been updated - Thank you!"
4065
+ msgstr "Thông tin tài khoản của bạn đã được cập nhật - Cám ơn bạn"
4066
+
4067
+ #: preheaders/account.php:12 preheaders/levels.php:24 preheaders/account.php:11
4068
+ #: preheaders/levels.php:23
4069
+ msgid "Sorry, your request could not be completed - please try again in a few moments."
4070
+ msgstr ""
4071
+ "Xin lỗi, yêu cầu của bạn không thể được hoàn thành - vui lòng thử lại sau vài phút."
4072
+
4073
+ #: preheaders/billing.php:270 preheaders/checkout.php:332 preheaders/billing.php:258
4074
+ #: preheaders/billing.php:265 preheaders/billing.php:266 preheaders/billing.php:279
4075
+ #: preheaders/checkout.php:458 preheaders/checkout.php:464 preheaders/checkout.php:465
4076
+ #: preheaders/checkout.php:470 preheaders/checkout.php:481 preheaders/checkout.php:482
4077
+ msgid "Please complete all required fields."
4078
+ msgstr "Vui lòng điền tất cả các trường bắt buộc."
4079
+
4080
+ #: preheaders/billing.php:273 preheaders/checkout.php:340 preheaders/billing.php:263
4081
+ #: preheaders/billing.php:268 preheaders/billing.php:269 preheaders/billing.php:284
4082
+ #: preheaders/checkout.php:466 preheaders/checkout.php:473 preheaders/checkout.php:474
4083
+ #: preheaders/checkout.php:478 preheaders/checkout.php:491 preheaders/checkout.php:492
4084
+ msgid "Your email addresses do not match. Please try again."
4085
+ msgstr "Địa chỉ email của bạn không phù hợp. Vui lòng thử lại."
4086
+
4087
+ #: preheaders/billing.php:276 preheaders/checkout.php:345 preheaders/billing.php:268
4088
+ #: preheaders/billing.php:271 preheaders/billing.php:272 preheaders/billing.php:289
4089
+ #: preheaders/checkout.php:471 preheaders/checkout.php:478 preheaders/checkout.php:480
4090
+ #: preheaders/checkout.php:483 preheaders/checkout.php:497 preheaders/checkout.php:498
4091
+ msgid "The email address entered is in an invalid format. Please try again."
4092
+ msgstr "Địa chỉ email đã nhập trong không hợp lệ. Vui lòng thử lại."
4093
+
4094
+ #: preheaders/billing.php:280 preheaders/billing.php:274 preheaders/billing.php:275
4095
+ #: preheaders/billing.php:276 preheaders/billing.php:295
4096
+ msgid "All good!"
4097
+ msgstr "Đã xong"
4098
+
4099
+ #: preheaders/billing.php:350 preheaders/billing.php:340 preheaders/billing.php:345
4100
+ #: preheaders/billing.php:346 preheaders/billing.php:370
4101
+ #, php-format
4102
+ msgid "Information updated. <a href=\"%s\">&laquo; back to my account</a>"
4103
+ msgstr "Thông tin được cập nhật. <a href=\"%s\"> &laquo; trở lại </a> tài khoản của tôi"
4104
+
4105
+ #: preheaders/billing.php:356 preheaders/billing.php:347 preheaders/billing.php:351
4106
+ #: preheaders/billing.php:352 preheaders/billing.php:378 preheaders/billing.php:380
4107
+ msgid "Error updating billing information."
4108
+ msgstr "Lỗi cập nhật thông tin thanh toán."
4109
+
4110
+ #: preheaders/cancel.php:28 preheaders/cancel.php:24 preheaders/cancel.php:25
4111
+ msgid "Your membership has been cancelled."
4112
+ msgstr "Thành viên của bạn đã bị hủy."
4113
+
4114
+ #: preheaders/checkout.php:32 preheaders/checkout.php:354 preheaders/checkout.php:28
4115
+ #: preheaders/checkout.php:30 preheaders/checkout.php:31 preheaders/checkout.php:480
4116
+ #: preheaders/checkout.php:487 preheaders/checkout.php:491 preheaders/checkout.php:492
4117
+ #: preheaders/checkout.php:508 preheaders/checkout.php:509
4118
+ msgid "Invalid gateway."
4119
+ msgstr "Cổng không hợp lệ."
4120
+
4121
+ #: preheaders/checkout.php:95 preheaders/checkout.php:88 preheaders/checkout.php:89
4122
+ #: preheaders/checkout.php:91 preheaders/checkout.php:96
4123
+ msgid "Checkout: Payment Information"
4124
+ msgstr "Thanh toán: Thông tin thanh toán"
4125
+
4126
+ #: preheaders/checkout.php:100
4127
+ msgid "Set Up Your Account"
4128
+ msgstr "Thiết lập Tài khoản Của Bạn"
4129
+
4130
+ #: preheaders/checkout.php:300 preheaders/checkout.php:416 preheaders/checkout.php:421
4131
+ msgid "There are JavaScript errors on the page. Please contact the webmaster."
4132
+ msgstr "Có lỗi JavaScript trên trang. Xin vui lòng liên hệ với webmaster."
4133
+
4134
+ #: preheaders/checkout.php:335 preheaders/checkout.php:461 preheaders/checkout.php:468
4135
+ #: preheaders/checkout.php:473 preheaders/checkout.php:485 preheaders/checkout.php:486
4136
+ msgid "Your passwords do not match. Please try again."
4137
+ msgstr "Mật khẩu của bạn không phù hợp. Vui lòng thử lại."
4138
+
4139
+ #: preheaders/checkout.php:350 preheaders/checkout.php:476 preheaders/checkout.php:483
4140
+ #: preheaders/checkout.php:486 preheaders/checkout.php:488 preheaders/checkout.php:503
4141
+ #: preheaders/checkout.php:504
4142
+ #, php-format
4143
+ msgid "Please check the box to agree to the %s."
4144
+ msgstr "Vui lòng đánh dấu vô hộp kiểm để đồng ý với %s."
4145
+
4146
+ #: preheaders/checkout.php:357 preheaders/checkout.php:483 preheaders/checkout.php:490
4147
+ #: preheaders/checkout.php:495 preheaders/checkout.php:512 preheaders/checkout.php:513
4148
+ msgid "Are you a spammer?"
4149
+ msgstr "Bạn có phải là spammer?"
4150
+
4151
+ #: preheaders/checkout.php:377 preheaders/checkout.php:503 preheaders/checkout.php:510
4152
+ #: preheaders/checkout.php:515 preheaders/checkout.php:518 preheaders/checkout.php:535
4153
+ #: preheaders/checkout.php:536
4154
+ msgid "That username is already taken. Please try another."
4155
+ msgstr "Tên người dùng mà đã được sử dụng. Hãy thử một cái khác."
4156
+
4157
+ #: preheaders/checkout.php:382 preheaders/checkout.php:508 preheaders/checkout.php:515
4158
+ #: preheaders/checkout.php:520 preheaders/checkout.php:524 preheaders/checkout.php:541
4159
+ #: preheaders/checkout.php:542
4160
+ msgid "That email address is already taken. Please try another."
4161
+ msgstr "Địa chỉ email này đã được sử dụng. Hãy thử một cái khác."
4162
+
4163
+ #: preheaders/checkout.php:416 preheaders/checkout.php:397 preheaders/checkout.php:399
4164
+ #: preheaders/checkout.php:525 preheaders/checkout.php:532 preheaders/checkout.php:537
4165
+ #: preheaders/checkout.php:544 preheaders/checkout.php:561 preheaders/checkout.php:562
4166
+ #, php-format
4167
+ msgid "reCAPTCHA failed. (%s) Please try again."
4168
+ msgstr ""
4169
+
4170
+ #: preheaders/checkout.php:501 preheaders/checkout.php:482 preheaders/checkout.php:484
4171
+ #: preheaders/checkout.php:647 preheaders/checkout.php:654 preheaders/checkout.php:659
4172
+ #: preheaders/checkout.php:683 preheaders/checkout.php:701 preheaders/checkout.php:702
4173
+ msgid "Payment accepted."
4174
+ msgstr "Thanh toán được chấp nhận."
4175
+
4176
+ #: preheaders/checkout.php:509 preheaders/checkout.php:490 preheaders/checkout.php:492
4177
+ #: preheaders/checkout.php:653 preheaders/checkout.php:660 preheaders/checkout.php:665
4178
+ #: preheaders/checkout.php:691 preheaders/checkout.php:709 preheaders/checkout.php:710
4179
+ msgid "Unknown error generating account. Please contact us to set up your membership."
4180
+ msgstr ""
4181
+ "Lỗi đã xảy ra với việc tạo tài khoản. Hãy liên hệ với chúng tôi để thiết lập tài "
4182
+ "khoản thành viên cho bạn."
4183
+
4184
+ #: preheaders/checkout.php:571 preheaders/checkout.php:550 preheaders/checkout.php:552
4185
+ #: preheaders/checkout.php:569 preheaders/checkout.php:785 preheaders/checkout.php:792
4186
+ #: preheaders/checkout.php:797 preheaders/checkout.php:825 preheaders/checkout.php:844
4187
+ #: preheaders/checkout.php:859 preheaders/checkout.php:860
4188
+ msgid ""
4189
+ "Your payment was accepted, but there was an error setting up your account. Please "
4190
+ "contact us."
4191
+ msgstr ""
4192
+ "Thanh toán của bạn đã được chấp nhận, nhưng đã có lỗi khi thiết lập tài khoản của "
4193
+ "bạn. Hãy liên hệ với chúng tôi."
4194
+
4195
+ #: preheaders/checkout.php:712 preheaders/checkout.php:691 preheaders/checkout.php:693
4196
+ #: preheaders/checkout.php:710 preheaders/checkout.php:953 preheaders/checkout.php:960
4197
+ #: preheaders/checkout.php:970 preheaders/checkout.php:983 preheaders/checkout.php:1030
4198
+ #: preheaders/checkout.php:1045 preheaders/checkout.php:1046
4199
+ msgid ""
4200
+ "IMPORTANT: Something went wrong during membership creation. Your credit card "
4201
+ "authorized, but we cancelled the order immediately. You should not try to submit this "
4202
+ "form again. Please contact the site owner to fix this issue."
4203
+ msgstr ""
4204
+ "QUAN TRỌNG: Đã phát sinh lỗi quá trình tạo thành viên. Thẻ tín dụng của bạn được ủy "
4205
+ "quyền, nhưng chúng tôi hủy bỏ lệnh ngay lập tức. Bạn không nên cố gắng để gửi biểu "
4206
+ "mẫu này một lần nữa. Xin vui lòng liên hệ với chủ sở hữu trang web để khắc phục vấn "
4207
+ "đề này."
4208
+
4209
+ #: preheaders/checkout.php:715 preheaders/checkout.php:694 preheaders/checkout.php:696
4210
+ #: preheaders/checkout.php:713 preheaders/checkout.php:956 preheaders/checkout.php:963
4211
+ #: preheaders/checkout.php:973 preheaders/checkout.php:988 preheaders/checkout.php:1035
4212
+ #: preheaders/checkout.php:1050 preheaders/checkout.php:1051
4213
+ msgid ""
4214
+ "IMPORTANT: Something went wrong during membership creation. Your credit card was "
4215
+ "charged, but we couldn't assign your membership. You should not submit this form "
4216
+ "again. Please contact the site owner to fix this issue."
4217
+ msgstr ""
4218
+ "QUAN TRỌNG: Đã phát sinh lỗi trong quá trình tạo thành viên. Thẻ tín dụng của bạn đã "
4219
+ "được tính phí, nhưng chúng tôi không thể chỉ định loại thành viên cho bạn. Bạn không "
4220
+ "cần phải nộp mẫu đơn này một lần nữa. Xin vui lòng liên hệ với chủ sở hữu trang web "
4221
+ "để khắc phục vấn đề này."
4222
+
4223
+ #: preheaders/checkout.php:726 preheaders/checkout.php:705 preheaders/checkout.php:707
4224
+ #: preheaders/checkout.php:724 preheaders/checkout.php:967 preheaders/checkout.php:974
4225
+ #: preheaders/checkout.php:984 preheaders/checkout.php:1001 preheaders/checkout.php:1048
4226
+ #: preheaders/checkout.php:1063 preheaders/checkout.php:1064
4227
+ #, php-format
4228
+ msgid ""
4229
+ "You must <a href=\"%s\">set up a Payment Gateway</a> before any payments will be "
4230
+ "processed."
4231
+ msgstr ""
4232
+ "Bạn phải <a href=\"%s\">Thiết lập cổng thanh toán</a> trước khi bất kỳ thanh toán nào "
4233
+ "được xử lý"
4234
+
4235
+ #: preheaders/checkout.php:728 preheaders/checkout.php:707 preheaders/checkout.php:709
4236
+ #: preheaders/checkout.php:726 preheaders/checkout.php:969 preheaders/checkout.php:976
4237
+ #: preheaders/checkout.php:986 preheaders/checkout.php:1003 preheaders/checkout.php:1050
4238
+ #: preheaders/checkout.php:1065 preheaders/checkout.php:1066
4239
+ msgid "A Payment Gateway must be set up before any payments will be processed."
4240
+ msgstr ""
4241
+ "Một Cổng thanh toán phải được thiết lập trước khi bất kỳ khoản thanh toán sẽ được xử "
4242
+ "lý."
4243
+
4244
+ #: scheduled/crons.php:38 scheduled/crons.php:31 scheduled/crons.php:34
4245
+ #: scheduled/crons.php:61
4246
+ #, php-format
4247
+ msgid "Membership expired email sent to %s. "
4248
+ msgstr "Tài khoản Thành viên đã hết hạn, email đã gửi đến %s. "
4249
+
4250
+ #: scheduled/crons.php:84 scheduled/crons.php:27 scheduled/crons.php:74
4251
+ #: scheduled/crons.php:80
4252
+ #, php-format
4253
+ msgid "Membership expiring email sent to %s. "
4254
+ msgstr "Tài khoản Thành viên đanlg hết hạn, email đã gửi đến %s. "
4255
+
4256
+ #: scheduled/crons.php:157 scheduled/crons.php:143 scheduled/crons.php:152
4257
+ #, php-format
4258
+ msgid "Credit card expiring email sent to %s. "
4259
+ msgstr "Thẻ tín dụng đang hết hạn, email đã gửi đến %s. "
4260
+
4261
+ #: scheduled/crons.php:210 scheduled/crons.php:104 scheduled/crons.php:196
4262
+ #: scheduled/crons.php:208
4263
+ #, php-format
4264
+ msgid "Trial ending email sent to %s. "
4265
+ msgstr "Thời gian dung thử8 đã hết hạn, email đã gửi đến %s. "
4266
+
4267
+ #: services/applydiscountcode.php:67 services/applydiscountcode.php:64
4268
+ #, php-format
4269
+ msgid "The %s code has been applied to your order. "
4270
+ msgstr "Mã %s đã được áp dụng cho đơn hàng của bạn."
4271
+
4272
+ #: services/applydiscountcode.php:97 services/applydiscountcode.php:82
4273
+ #: services/applydiscountcode.php:83 services/applydiscountcode.php:86
4274
+ #, php-format
4275
+ msgid "The <strong>%s</strong> code has been applied to your order."
4276
+ msgstr "Mã <strong>%s</strong> đã được áp dụng cho đơn hàng của bạn."
4277
+
4278
+ #: services/authnet-silent-post.php:141 services/authnet-silent-post.php:133
4279
+ #: services/authnet-silent-post.php:138
4280
+ msgid ""
4281
+ "<p>A payment is being held for review within Authorize.net.</p><p>Payment Information "
4282
+ "From Authorize.net"
4283
+ msgstr ""
4284
+
4285
+ #: services/stripe-webhook.php:270 services/stripe-webhook.php:176
4286
+ #: services/stripe-webhook.php:194
4287
+ #, php-format
4288
+ msgid ""
4289
+ "%s has had their payment subscription cancelled by Stripe. Please check that this "
4290
+ "user's membership is cancelled on your site if it should be."
4291
+ msgstr ""
4292
+
4293
+ #: shortcodes/pmpro_account.php:45 pages/account.php:19
4294
+ msgid "Billing"
4295
+ msgstr "Thông tin thanh toán "
4296
+
4297
+ #: shortcodes/pmpro_account.php:62 pages/account.php:36
4298
+ msgid "Update Billing Info"
4299
+ msgstr "Cập nhật thông tin thanh toán "
4300
+
4301
+ #: shortcodes/pmpro_account.php:68 pages/account.php:42
4302
+ msgid "Change"
4303
+ msgstr "Thay đổi"
4304
+
4305
+ #: shortcodes/pmpro_account.php:90 pages/account.php:64
4306
+ msgid "View all Membership Options"
4307
+ msgstr "Xem tất cả loại thành viên"
4308
+
4309
+ #: shortcodes/pmpro_account.php:99 pages/account.php:46 pages/account.php:50
4310
+ #: pages/account.php:71
4311
+ msgid "My Account"
4312
+ msgstr "Tài khoản của tôi"
4313
+
4314
+ #: shortcodes/pmpro_account.php:110 pages/account.php:55 pages/account.php:59
4315
+ #: pages/account.php:80
4316
+ msgid "Edit Profile"
4317
+ msgstr "Sửa thông tin cá nhân"
4318
+
4319
+ #: shortcodes/pmpro_account.php:111 pages/account.php:56 pages/account.php:60
4320
+ #: pages/account.php:81
4321
+ msgid "Change Password"
4322
+ msgstr "Đổi mật khẩu"
4323
+
4324
+ #: shortcodes/pmpro_account.php:118 pages/account.php:87 pages/account.php:125
4325
+ #: pages/account.php:129
4326
+ msgid "Past Invoices"
4327
+ msgstr "Hóa đơn trước đó "
4328
+
4329
+ #: shortcodes/pmpro_account.php:124 pages/account.php:93
4330
+ msgid "Amount"
4331
+ msgstr "Số lượng"
4332
+
4333
+ #: shortcodes/pmpro_account.php:152 pages/account.php:121 pages/account.php:140
4334
+ #: pages/account.php:144
4335
+ msgid "View All Invoices"
4336
+ msgstr "Xem tất cả các hoá đơn"
4337
+
4338
+ #: shortcodes/pmpro_account.php:159 pages/account.php:128 pages/account.php:146
4339
+ #: pages/account.php:150
4340
+ msgid "Member Links"
4341
+ msgstr "Các kiên kết của thành viên"
4342
+
4343
+ #: adminpages/addons.php:79
4344
+ msgid "Disabled"
4345
+ msgstr "Không cho phép"
4346
+
4347
+ #: adminpages/addons.php:79
4348
+ msgid "Enabled"
4349
+ msgstr "Cho phép"
4350
+
4351
+ #: adminpages/discountcodes.php:437
4352
+ msgid "Billing Ammount"
4353
+ msgstr "Số lượng thanh toán"
4354
+
4355
+ #: adminpages/discountcodes.php:480
4356
+ msgid "Check this to set an expiration date for new sign ups."
4357
+ msgstr "Đánh dấu để thiết lập ngày hết hạn cho đăng ký mới."
4358
+
4359
+ #: adminpages/discountcodes.php:497
4360
+ msgid ""
4361
+ "How long before the expiration expires. Note that any future payments will be "
4362
+ "cancelled when the membership expires."
4363
+ msgstr ""
4364
+ "Bao lâu trước khi kết thúc thời hạn hết hạn. Lưu ý rằng bất kỳ khoản thanh toán nào "
4365
+ "trong tương lai sẽ bị hủy khi thành viên hết hạn."
4366
+
4367
+ #: adminpages/membershiplevels.php:364
4368
+ msgid ""
4369
+ "Stripe integration currently only supports billing periods of \"Month\" or \"Year\"."
4370
+ msgstr ""
4371
+
4372
+ #: adminpages/membershiplevels.php:398
4373
+ msgid ""
4374
+ "2Checkout integration does not currently support custom trials. You can do one period "
4375
+ "trials by setting an initial payment different from the billing amount."
4376
+ msgstr ""
4377
+
4378
+ #: adminpages/membershiplevels.php:508 adminpages/membershiplevels.php:514
4379
+ #: adminpages/membershiplevels.php:516 adminpages/membershiplevels.php:543
4380
+ msgid "Billing Cycle"
4381
+ msgstr "Kỳ hạn"
4382
+
4383
+ #: adminpages/membershiplevels.php:509 adminpages/membershiplevels.php:515
4384
+ #: adminpages/membershiplevels.php:517 adminpages/membershiplevels.php:544
4385
+ msgid "Trial Cycle"
4386
+ msgstr "Kỳ hạn dung thử"
4387
+
4388
+ #: adminpages/membershiplevels.php:543 adminpages/membershiplevels.php:549
4389
+ #: adminpages/membershiplevels.php:551 adminpages/membershiplevels.php:578
4390
+ msgid "every"
4391
+ msgstr "mọi"
4392
+
4393
+ #: adminpages/membershiplevels.php:566 adminpages/membershiplevels.php:572
4394
+ #: adminpages/membershiplevels.php:574 adminpages/membershiplevels.php:580
4395
+ #: adminpages/membershiplevels.php:601 adminpages/membershiplevels.php:660
4396
+ #, php-format
4397
+ msgid ""
4398
+ "Are you sure you want to delete membership level %s? All subscriptions will be "
4399
+ "cancelled."
4400
+ msgstr "Bạn có chắc chắn muốn xóa cấp thành viên %s? Tất cả các đăng ký sẽ bị hủy bỏ."
4401
+
4402
+ #: adminpages/memberslist.php:184 adminpages/memberslist.php:212
4403
+ msgid "Never"
4404
+ msgstr "Không bao giờ"
4405
+
4406
+ #: adminpages/paymentsettings.php:170
4407
+ msgid ""
4408
+ "Payflow Pro currently only supports one-time payments. Users will not be able to "
4409
+ "checkout for levels with recurring payments."
4410
+ msgstr ""
4411
+
4412
+ #: adminpages/paymentsettings.php:405 adminpages/paymentsettings.php:445
4413
+ msgid ""
4414
+ "If values are given, tax will be applied for any members ordering from the selected "
4415
+ "state. For more complex tax rules, use the \"pmpro_tax\" filter."
4416
+ msgstr ""
4417
+
4418
+ #: adminpages/paymentsettings.php:410 adminpages/paymentsettings.php:421
4419
+ msgid "Use SSL"
4420
+ msgstr ""
4421
+
4422
+ #: adminpages/paymentsettings.php:425
4423
+ msgid "Required by this Gateway Option"
4424
+ msgstr ""
4425
+
4426
+ #: adminpages/paymentsettings.php:432
4427
+ msgid ""
4428
+ "Stripe doesn't require billing address fields. Choose 'No' to hide them on the "
4429
+ "checkout page."
4430
+ msgstr ""
4431
+
4432
+ #: adminpages/paymentsettings.php:438 adminpages/paymentsettings.php:471
4433
+ #: adminpages/paymentsettings.php:477 adminpages/paymentsettings.php:479
4434
+ msgid "HTTPS Nuclear Option"
4435
+ msgstr ""
4436
+
4437
+ #: adminpages/paymentsettings.php:441 adminpages/paymentsettings.php:474
4438
+ #: adminpages/paymentsettings.php:480 adminpages/paymentsettings.php:482
4439
+ msgid ""
4440
+ "Use the \"Nuclear Option\" to use secure (HTTPS) URLs on your secure pages. Check "
4441
+ "this if you are using SSL and have warnings on your checkout pages."
4442
+ msgstr ""
4443
+
4444
+ #: adminpages/paymentsettings.php:490 adminpages/paymentsettings.php:496
4445
+ #: adminpages/paymentsettings.php:498
4446
+ #: classes/gateways/class.pmprogateway_twocheckout.php:148
4447
+ msgid "To fully integrate with 2Checkout, be sure to set your 2Checkout INS URL "
4448
+ msgstr ""
4449
+
4450
+ #: classes/class.pmproemail.php:685 classes/class.pmproemail.php:734
4451
+ #: classes/class.pmproemail.php:799
4452
+ msgid "membership has been cancelled"
4453
+ msgstr "quyền thành viên đã bị hủy"
4454
+
4455
+ #: includes/currencies.php:11
4456
+ msgid "Brazilian Real (&#36;)"
4457
+ msgstr ""
4458
+
4459
+ #: includes/currencies.php:29 includes/currencies.php:49
4460
+ msgid "South African Rand"
4461
+ msgstr ""
4462
+
4463
+ #: includes/profile.php:82 includes/profile.php:84
4464
+ msgid "User is not paying."
4465
+ msgstr "Thành viên chưa trả phí "
4466
+
4467
+ #: pages/account.php:10
4468
+ msgid "Your membership is <strong>active</strong>."
4469
+ msgstr "Quyền thành viên của bạn được <strong>kích hoạt</strong>."
4470
+
4471
+ #: pages/account.php:34 pages/account.php:38
4472
+ #, php-format
4473
+ msgid "Your first payment will cost %s."
4474
+ msgstr "Khoản thanh toán đầu tiên là %s."
4475
+
4476
+ #: pages/account.php:38 pages/account.php:42
4477
+ #, php-format
4478
+ msgid "Your first %d payments will cost %s."
4479
+ msgstr "Khoản thanh toán đầu tiên %d là %s."
4480
+
4481
+ #: pages/account.php:87 pages/account.php:91
4482
+ msgid "Billing Information"
4483
+ msgstr "Thông tin thanh toán"
4484
+
4485
+ #: pages/account.php:114 pages/account.php:118
4486
+ msgid "Edit Billing Information"
4487
+ msgstr "Sửa thông tin thanh toán"
4488
+
4489
+ #: pages/account.php:152 pages/account.php:156
4490
+ msgid "Update Billing Information"
4491
+ msgstr "Cập nhật thông tin thanh toán"
4492
+
4493
+ #: pages/account.php:155 pages/account.php:159
4494
+ msgid "Change Membership Level"
4495
+ msgstr "Thay đổi loại Thành Viên"
4496
+
4497
+ #: pages/account.php:157 pages/account.php:161
4498
+ msgid "Cancel Membership"
4499
+ msgstr "Hủy quyển thành viên"
4500
+
4501
+ #: pages/checkout.php:51 pages/checkout.php:52
4502
+ #, php-format
4503
+ msgid "<p>The <strong>%s</strong> code has been applied to your order.</p>"
4504
+ msgstr "<p>M ã <strong>%s</strong> đã được áp dụng cho đơn hàng của bạn.</p>"
4505
+
4506
+ #: pages/checkout.php:688 pages/checkout.php:691 pages/checkout.php:707
4507
+ msgid "Submit and Pay with 2CheckOut"
4508
+ msgstr "Submit and Pay with 2CheckOut"
4509
+
4510
+ #: pages/confirmation.php:12
4511
+ msgid ""
4512
+ "Your payment has been submitted to PayPal. Your membership will be activated shortly."
4513
+ msgstr ""
4514
+ "Thanh toán của bạn đã được gửi cho PayPal. Tài khoản thành viên của bạn sẽ được kích "
4515
+ "hoạt sớm. "
4516
+
4517
+ #: pages/confirmation.php:95 pages/confirmation.php:97
4518
+ #, php-format
4519
+ msgid ""
4520
+ "Below are details about your membership account. A welcome email with has been sent "
4521
+ "to %s."
4522
+ msgstr ""
4523
+ "Dưới đây là chi tiết về tài khoản thành viên của bạn. Một email chào mừng đã được gửi "
4524
+ "đến %s."
4525
+
4526
+ #: pages/invoice.php:120 pages/invoice.php:122
4527
+ msgid "View Invoice"
4528
+ msgstr "Xem hóa đơn "
4529
+
4530
+ #: pages/levels.php:15
4531
+ msgid "Subscription Information"
4532
+ msgstr "Thông tin đăng ký "
4533
+
4534
+ #: pages/levels.php:33
4535
+ msgid "--"
4536
+ msgstr "..."
4537
+
4538
+ #: pages/levels.php:51
4539
+ #, php-format
4540
+ msgid "%s per %s for %d more %s."
4541
+ msgstr "%s mỗi %s cho %d thêm %s."
4542
+
4543
+ #: pages/levels.php:55
4544
+ #, php-format
4545
+ msgid "%s every %d %s for %d more %s."
4546
+ msgstr "%s các %d %s cho %d thêm %s."
4547
+
4548
+ #: pages/levels.php:60
4549
+ #, php-format
4550
+ msgid "%s after %d %s."
4551
+ msgstr "%s sau %d %s."
4552
+
4553
+ #: preheaders/checkout.php:99 preheaders/checkout.php:100 preheaders/checkout.php:102
4554
+ #: preheaders/checkout.php:109
4555
+ msgid "Set up Your Account"
4556
+ msgstr "Thiết lập tài khoản"
pages/checkout.php CHANGED
@@ -291,10 +291,14 @@
291
  <tr>
292
  <td>
293
  <div>
294
- <input type="radio" name="gateway" value="paypal" <?php if(!$gateway || $gateway == "paypal") { ?>checked="checked"<?php } ?> />
295
- <a href="javascript:void(0);" class="pmpro_radio"><?php _e('Check Out with a Credit Card Here', 'pmpro');?></a> &nbsp;
296
- <input type="radio" name="gateway" value="paypalexpress" <?php if($gateway == "paypalexpress") { ?>checked="checked"<?php } ?> />
297
- <a href="javascript:void(0);" class="pmpro_radio"><?php _e('Check Out with PayPal', 'pmpro');?></a> &nbsp;
 
 
 
 
298
  </div>
299
  </td>
300
  </tr>
291
  <tr>
292
  <td>
293
  <div>
294
+ <span class="gateway_paypal">
295
+ <input type="radio" name="gateway" value="paypal" <?php if(!$gateway || $gateway == "paypal") { ?>checked="checked"<?php } ?> />
296
+ <a href="javascript:void(0);" class="pmpro_radio"><?php _e('Check Out with a Credit Card Here', 'pmpro');?></a>
297
+ </span>
298
+ <span class="gateway_paypalexpress">
299
+ <input type="radio" name="gateway" value="paypalexpress" <?php if($gateway == "paypalexpress") { ?>checked="checked"<?php } ?> />
300
+ <a href="javascript:void(0);" class="pmpro_radio"><?php _e('Check Out with PayPal', 'pmpro');?></a>
301
+ </span>
302
  </div>
303
  </td>
304
  </tr>
paid-memberships-pro.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Paid Memberships Pro
4
  Plugin URI: http://www.paidmembershipspro.com
5
  Description: Plugin to Handle Memberships
6
- Version: 1.8.5.6
7
  Author: Stranger Studios
8
  Author URI: http://www.strangerstudios.com
9
  */
@@ -13,7 +13,7 @@ Author URI: http://www.strangerstudios.com
13
  */
14
 
15
  //version constant
16
- define("PMPRO_VERSION", "1.8.5.6");
17
 
18
  //if the session has been started yet, start it (ignore if running from command line)
19
  if(defined('STDIN') )
3
  Plugin Name: Paid Memberships Pro
4
  Plugin URI: http://www.paidmembershipspro.com
5
  Description: Plugin to Handle Memberships
6
+ Version: 1.8.6.2
7
  Author: Stranger Studios
8
  Author URI: http://www.strangerstudios.com
9
  */
13
  */
14
 
15
  //version constant
16
+ define("PMPRO_VERSION", "1.8.6.2");
17
 
18
  //if the session has been started yet, start it (ignore if running from command line)
19
  if(defined('STDIN') )
preheaders/checkout.php CHANGED
@@ -1,754 +1,756 @@
1
- <?php
2
- global $post, $gateway, $wpdb, $besecure, $discount_code, $discount_code_id, $pmpro_level, $pmpro_levels, $pmpro_msg, $pmpro_msgt, $pmpro_review, $skip_account_fields, $pmpro_paypal_token, $pmpro_show_discount_code, $pmpro_error_fields, $pmpro_required_billing_fields, $pmpro_required_user_fields, $wp_version, $current_user;
3
-
4
- //make sure we know current user's membership level
5
- if ($current_user->ID)
6
- $current_user->membership_level = pmpro_getMembershipLevelForUser($current_user->ID);
7
-
8
- //this var stores fields with errors so we can make them red on the frontend
9
- $pmpro_error_fields = array();
10
-
11
- //blank array for required fields, set below
12
- $pmpro_required_billing_fields = array();
13
- $pmpro_required_user_fields = array();
14
-
15
- //was a gateway passed?
16
- if (!empty($_REQUEST['gateway']))
17
- $gateway = $_REQUEST['gateway'];
18
- elseif (!empty($_REQUEST['review']))
19
- $gateway = "paypalexpress";
20
- else
21
- $gateway = pmpro_getOption("gateway");
22
-
23
- //set valid gateways - the active gateway in the settings and any gateway added through the filter will be allowed
24
- if (pmpro_getOption("gateway", true) == "paypal")
25
- $valid_gateways = apply_filters("pmpro_valid_gateways", array("paypal", "paypalexpress"));
26
- else
27
- $valid_gateways = apply_filters("pmpro_valid_gateways", array(pmpro_getOption("gateway", true)));
28
-
29
- //let's add an error now, if an invalid gateway is set
30
- if (!in_array($gateway, $valid_gateways))
31
- {
32
- $pmpro_msg = __("Invalid gateway.", 'pmpro');
33
- $pmpro_msgt = "pmpro_error";
34
- }
35
-
36
- //what level are they purchasing? (discount code passed)
37
- if (!empty($_REQUEST['level']) && !empty($_REQUEST['discount_code'])) {
38
- $discount_code = preg_replace("/[^A-Za-z0-9\-]/", "", $_REQUEST['discount_code']);
39
- $discount_code_id = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_discount_codes WHERE code = '" . $discount_code . "' LIMIT 1");
40
-
41
- //check code
42
- $code_check = pmpro_checkDiscountCode($discount_code, (int)$_REQUEST['level'], true);
43
- if ($code_check[0] == false) {
44
- //error
45
- $pmpro_msg = $code_check[1];
46
- $pmpro_msgt = "pmpro_error";
47
-
48
- //don't use this code
49
- $use_discount_code = false;
50
- } else {
51
- $sqlQuery = "SELECT l.id, cl.*, l.name, l.description, l.allow_signups FROM $wpdb->pmpro_discount_codes_levels cl LEFT JOIN $wpdb->pmpro_membership_levels l ON cl.level_id = l.id LEFT JOIN $wpdb->pmpro_discount_codes dc ON dc.id = cl.code_id WHERE dc.code = '" . $discount_code . "' AND cl.level_id = '" . (int)$_REQUEST['level'] . "' LIMIT 1";
52
- $pmpro_level = $wpdb->get_row($sqlQuery);
53
-
54
- //if the discount code doesn't adjust the level, let's just get the straight level
55
- if (empty($pmpro_level))
56
- $pmpro_level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . (int)$_REQUEST['level'] . "' LIMIT 1");
57
-
58
- //filter adjustments to the level
59
- $pmpro_level->code_id = $discount_code_id;
60
- $pmpro_level = apply_filters("pmpro_discount_code_level", $pmpro_level, $discount_code_id);
61
-
62
- $use_discount_code = true;
63
- }
64
- }
65
-
66
- //what level are they purchasing? (no discount code)
67
- if (empty($pmpro_level) && !empty($_REQUEST['level'])) {
68
- $pmpro_level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . esc_sql($_REQUEST['level']) . "' AND allow_signups = 1 LIMIT 1");
69
- } elseif (empty($pmpro_level)) {
70
- //check if a level is defined in custom fields
71
- $default_level = get_post_meta($post->ID, "pmpro_default_level", true);
72
- if (!empty($default_level))
73
- {
74
- $pmpro_level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . esc_sql($default_level) . "' AND allow_signups = 1 LIMIT 1");
75
- }
76
- }
77
-
78
- //filter the level (for upgrades, etc)
79
- $pmpro_level = apply_filters("pmpro_checkout_level", $pmpro_level);
80
-
81
- if (empty($pmpro_level->id))
82
- {
83
- wp_redirect(pmpro_url("levels"));
84
- exit(0);
85
- }
86
-
87
- //enqueue some scripts
88
- wp_enqueue_script('jquery.creditCardValidator', plugins_url('/js/jquery.creditCardValidator.js' , dirname(__FILE__ )), array( 'jquery' ));
89
-
90
- global $wpdb, $current_user, $pmpro_requirebilling;
91
- //unless we're submitting a form, let's try to figure out if https should be used
92
-
93
- if (!pmpro_isLevelFree($pmpro_level)) {
94
- //require billing and ssl
95
- $pagetitle = __("Checkout: Payment Information", 'pmpro');
96
- $pmpro_requirebilling = true;
97
- $besecure = pmpro_getOption("use_ssl");
98
- } else {
99
- //no payment so we don't need ssl
100
- $pagetitle = __("Set Up Your Account", 'pmpro');
101
- $pmpro_requirebilling = false;
102
- $besecure = false;
103
- }
104
-
105
- //in case a discount code was used or something else made the level free, but we're already over ssl
106
- if (!$besecure && !empty($_REQUEST['submit-checkout']) && is_ssl())
107
- $besecure = true; //be secure anyway since we're already checking out
108
-
109
- //action to run extra code for gateways/etc
110
- do_action('pmpro_checkout_preheader');
111
-
112
- //get all levels in case we need them
113
- global $pmpro_levels;
114
- $pmpro_levels = pmpro_getAllLevels();
115
-
116
- //should we show the discount code field?
117
- if ($wpdb->get_var("SELECT id FROM $wpdb->pmpro_discount_codes LIMIT 1"))
118
- $pmpro_show_discount_code = true;
119
- else
120
- $pmpro_show_discount_code = false;
121
- $pmpro_show_discount_code = apply_filters("pmpro_show_discount_code", $pmpro_show_discount_code);
122
-
123
- //by default we show the account fields if the user isn't logged in
124
- if ($current_user->ID) {
125
- $skip_account_fields = true;
126
- } else {
127
- $skip_account_fields = false;
128
- }
129
- //in case people want to have an account created automatically
130
- $skip_account_fields = apply_filters("pmpro_skip_account_fields", $skip_account_fields, $current_user);
131
-
132
- //some options
133
- global $tospage;
134
- $tospage = pmpro_getOption("tospage");
135
- if ($tospage)
136
- $tospage = get_post($tospage);
137
-
138
- //load em up (other fields)
139
- global $username, $password, $password2, $bfirstname, $blastname, $baddress1, $baddress2, $bcity, $bstate, $bzipcode, $bcountry, $bphone, $bemail, $bconfirmemail, $CardType, $AccountNumber, $ExpirationMonth, $ExpirationYear;
140
-
141
- if (isset($_REQUEST['order_id']))
142
- $order_id = intval($_REQUEST['order_id']);
143
- else
144
- $order_id = "";
145
- if (isset($_REQUEST['bfirstname']))
146
- $bfirstname = sanitize_text_field(stripslashes($_REQUEST['bfirstname']));
147
- else
148
- $bfirstname = "";
149
- if (isset($_REQUEST['blastname']))
150
- $blastname = sanitize_text_field(stripslashes($_REQUEST['blastname']));
151
- else
152
- $blastname = "";
153
- if (isset($_REQUEST['fullname']))
154
- $fullname = $_REQUEST['fullname']; //honeypot for spammers
155
- if (isset($_REQUEST['baddress1']))
156
- $baddress1 = sanitize_text_field(stripslashes($_REQUEST['baddress1']));
157
- else
158
- $baddress1 = "";
159
- if (isset($_REQUEST['baddress2']))
160
- $baddress2 = sanitize_text_field(stripslashes($_REQUEST['baddress2']));
161
- else
162
- $baddress2 = "";
163
- if (isset($_REQUEST['bcity']))
164
- $bcity = sanitize_text_field(stripslashes($_REQUEST['bcity']));
165
- else
166
- $bcity = "";
167
-
168
- if (isset($_REQUEST['bstate']))
169
- $bstate = sanitize_text_field(stripslashes($_REQUEST['bstate']));
170
- else
171
- $bstate = "";
172
-
173
- //convert long state names to abbreviations
174
- if (!empty($bstate))
175
- {
176
- global $pmpro_states;
177
- foreach($pmpro_states as $abbr => $state)
178
- {
179
- if ($bstate == $state)
180
- {
181
- $bstate = $abbr;
182
- break;
183
- }
184
- }
185
- }
186
-
187
- if (isset($_REQUEST['bzipcode']))
188
- $bzipcode = sanitize_text_field(stripslashes($_REQUEST['bzipcode']));
189
- else
190
- $bzipcode = "";
191
- if (isset($_REQUEST['bcountry']))
192
- $bcountry = sanitize_text_field(stripslashes($_REQUEST['bcountry']));
193
- else
194
- $bcountry = "";
195
- if (isset($_REQUEST['bphone']))
196
- $bphone = sanitize_text_field(stripslashes($_REQUEST['bphone']));
197
- else
198
- $bphone = "";
199
- if (isset($_REQUEST['bemail']))
200
- $bemail = sanitize_email(stripslashes($_REQUEST['bemail']));
201
- else
202
- $bemail = "";
203
- if (isset($_REQUEST['bconfirmemail_copy']))
204
- $bconfirmemail = $bemail;
205
- elseif (isset($_REQUEST['bconfirmemail']))
206
- $bconfirmemail = sanitize_email(stripslashes($_REQUEST['bconfirmemail']));
207
- else
208
- $bconfirmemail = "";
209
-
210
- if (isset($_REQUEST['CardType']) && !empty($_REQUEST['AccountNumber']))
211
- $CardType = sanitize_text_field($_REQUEST['CardType']);
212
- else
213
- $CardType = "";
214
- if (isset($_REQUEST['AccountNumber']))
215
- $AccountNumber = sanitize_text_field($_REQUEST['AccountNumber']);
216
- else
217
- $AccountNumber = "";
218
-
219
- if (isset($_REQUEST['ExpirationMonth']))
220
- $ExpirationMonth = sanitize_text_field($_REQUEST['ExpirationMonth']);
221
- else
222
- $ExpirationMonth = "";
223
- if (isset($_REQUEST['ExpirationYear']))
224
- $ExpirationYear = sanitize_text_field($_REQUEST['ExpirationYear']);
225
- else
226
- $ExpirationYear = "";
227
- if (isset($_REQUEST['CVV']))
228
- $CVV = sanitize_text_field($_REQUEST['CVV']);
229
- else
230
- $CVV = "";
231
-
232
- if (isset($_REQUEST['discount_code']))
233
- $discount_code = sanitize_text_field($_REQUEST['discount_code']);
234
- else
235
- $discount_code = "";
236
- if (isset($_REQUEST['username']))
237
- $username = sanitize_user($_REQUEST['username']);
238
- else
239
- $username = "";
240
- if (isset($_REQUEST['password']))
241
- $password = $_REQUEST['password'];
242
- else
243
- $password = "";
244
- if (isset($_REQUEST['password2_copy']))
245
- $password2 = $password;
246
- elseif (isset($_REQUEST['password2']))
247
- $password2 = $_REQUEST['password2'];
248
- else
249
- $password2 = "";
250
- if (isset($_REQUEST['tos']))
251
- $tos = intval($_REQUEST['tos']);
252
- else
253
- $tos = "";
254
-
255
- //_x stuff in case they clicked on the image button with their mouse
256
- if (isset($_REQUEST['submit-checkout']))
257
- $submit = $_REQUEST['submit-checkout'];
258
- if (empty($submit) && isset($_REQUEST['submit-checkout_x']) )
259
- $submit = $_REQUEST['submit-checkout_x'];
260
- if (isset($submit) && $submit === "0")
261
- $submit = true;
262
- elseif (!isset($submit))
263
- $submit = false;
264
-
265
- //require fields
266
- $pmpro_required_billing_fields = array(
267
- "bfirstname" => $bfirstname,
268
- "blastname" => $blastname,
269
- "baddress1" => $baddress1,
270
- "bcity" => $bcity,
271
- "bstate" => $bstate,
272
- "bzipcode" => $bzipcode,
273
- "bphone" => $bphone,
274
- "bemail" => $bemail,
275
- "bcountry" => $bcountry,
276
- "CardType" => $CardType,
277
- "AccountNumber" => $AccountNumber,
278
- "ExpirationMonth" => $ExpirationMonth,
279
- "ExpirationYear" => $ExpirationYear,
280
- "CVV" => $CVV
281
- );
282
- $pmpro_required_billing_fields = apply_filters("pmpro_required_billing_fields", $pmpro_required_billing_fields);
283
- $pmpro_required_user_fields = array(
284
- "username" => $username,
285
- "password" => $password,
286
- "password2" => $password2,
287
- "bemail" => $bemail,
288
- "bconfirmemail" => $bconfirmemail
289
- );
290
- $pmpro_required_user_fields = apply_filters("pmpro_required_user_fields", $pmpro_required_user_fields);
291
-
292
- //pmpro_confirmed is set to true later if payment goes through
293
- $pmpro_confirmed = false;
294
-
295
- //check their fields if they clicked continue
296
- if ($submit && $pmpro_msgt != "pmpro_error") {
297
-
298
- //make sure javascript is ok
299
- if (apply_filters("pmpro_require_javascript_for_checkout", true) && !empty($_REQUEST['checkjavascript']) && empty($_REQUEST['javascriptok'])) {
300
- pmpro_setMessage(__("There are JavaScript errors on the page. Please contact the webmaster.", "pmpro"), "pmpro_error");
301
- }
302
-
303
- //if we're skipping the account fields and there is no user, we need to create a username and password
304
- if ($skip_account_fields && !$current_user->ID) {
305
- $username = pmpro_generateUsername($bfirstname, $blastname, $bemail);
306
- if (empty($username))
307
- $username = pmpro_getDiscountCode();
308
- $password = pmpro_getDiscountCode() . pmpro_getDiscountCode(); //using two random discount codes
309
- $password2 = $password;
310
- }
311
-
312
- //check billing fields
313
- if ($pmpro_requirebilling) {
314
- //filter
315
- foreach($pmpro_required_billing_fields as $key => $field) {
316
- if (!$field) {
317
- $pmpro_error_fields[] = $key;
318
- }
319
- }
320
- }
321
-
322
- //check user fields
323
- if (empty($current_user->ID)) {
324
- foreach($pmpro_required_user_fields as $key => $field) {
325
- if (!$field) {
326
- $pmpro_error_fields[] = $key;
327
- }
328
- }
329
- }
330
-
331
- if (!empty($pmpro_error_fields)) {
332
- pmpro_setMessage(__("Please complete all required fields.", "pmpro"), "pmpro_error");
333
- }
334
- if (!empty($password) && $password != $password2) {
335
- pmpro_setMessage(__("Your passwords do not match. Please try again.", "pmpro"), "pmpro_error");
336
- $pmpro_error_fields[] = "password";
337
- $pmpro_error_fields[] = "password2";
338
- }
339
- if (!empty($bemail) && $bemail != $bconfirmemail) {
340
- pmpro_setMessage(__("Your email addresses do not match. Please try again.", "pmpro"), "pmpro_error");
341
- $pmpro_error_fields[] = "bemail";
342
- $pmpro_error_fields[] = "bconfirmemail";
343
- }
344
- if (!empty($bemail) && !is_email($bemail)) {
345
- pmpro_setMessage(__("The email address entered is in an invalid format. Please try again.", "pmpro"), "pmpro_error");
346
- $pmpro_error_fields[] = "bemail";
347
- $pmpro_error_fields[] = "bconfirmemail";
348
- }
349
- if (!empty($tospage) && empty($tos)) {
350
- pmpro_setMessage(sprintf(__("Please check the box to agree to the %s.", "pmpro"), $tospage->post_title), "pmpro_error");
351
- $pmpro_error_fields[] = "tospage";
352
- }
353
- if (!in_array($gateway, $valid_gateways)) {
354
- pmpro_setMessage(__("Invalid gateway.", "pmpro"), "pmpro_error");
355
- }
356
- if (!empty($fullname)) {
357
- pmpro_setMessage(__("Are you a spammer?", "pmpro"), "pmpro_error");
358
- }
359
-
360
- if ($pmpro_msgt == "pmpro_error")
361
- $pmpro_continue_registration = false;
362
- else
363
- $pmpro_continue_registration = true;
364
- $pmpro_continue_registration = apply_filters("pmpro_registration_checks", $pmpro_continue_registration);
365
-
366
- if ($pmpro_continue_registration) {
367
- //if creating a new user, check that the email and username are available
368
- if (empty($current_user->ID)) {
369
- $oldusername = $wpdb->get_var("SELECT user_login FROM $wpdb->users WHERE user_login = '" . esc_sql($username) . "' LIMIT 1");
370
- $oldemail = $wpdb->get_var("SELECT user_email FROM $wpdb->users WHERE user_email = '" . esc_sql($bemail) . "' LIMIT 1");
371
-
372
- //this hook can be used to allow multiple accounts with the same email address
373
- $oldemail = apply_filters("pmpro_checkout_oldemail", $oldemail);
374
- }
375
-
376
- if (!empty($oldusername)) {
377
- pmpro_setMessage(__("That username is already taken. Please try another.", "pmpro"), "pmpro_error");
378
- $pmpro_error_fields[] = "username";
379
- }
380
-
381
- if (!empty($oldemail)) {
382
- pmpro_setMessage(__("That email address is already taken. Please try another.", "pmpro"), "pmpro_error");
383
- $pmpro_error_fields[] = "bemail";
384
- $pmpro_error_fields[] = "bconfirmemail";
385
- }
386
-
387
- //only continue if there are no other errors yet
388
- if ($pmpro_msgt != "pmpro_error") {
389
- //check recaptcha first
390
- global $recaptcha;
391
- if (!$skip_account_fields && ($recaptcha == 2 || ($recaptcha == 1 && pmpro_isLevelFree($pmpro_level)))) {
392
- global $recaptcha_privatekey;
393
-
394
- if(isset($_POST["recaptcha_challenge_field"]))
395
- {
396
- //using older recaptcha lib
397
- $resp = recaptcha_check_answer($recaptcha_privatekey,
398
- $_SERVER["REMOTE_ADDR"],
399
- $_POST["recaptcha_challenge_field"],
400
- $_POST["recaptcha_response_field"]);
401
-
402
- $recaptcha_valid = $resp->is_valid;
403
- $recaptcha_errors = $resp->error;
404
- }
405
- else
406
- {
407
- //using newer recaptcha lib
408
- $reCaptcha = new pmpro_ReCaptcha($recaptcha_privatekey);
409
- $resp = $reCaptcha->verifyResponse($_SERVER["REMOTE_ADDR"], $_POST["g-recaptcha-response"]);
410
-
411
- $recaptcha_valid = $resp->success;
412
- $recaptcha_errors = $resp->errorCodes;
413
- }
414
-
415
- if (!$recaptcha_valid) {
416
- $pmpro_msg = sprintf(__("reCAPTCHA failed. (%s) Please try again.", "pmpro"), $recaptcha_errors);
417
- $pmpro_msgt = "pmpro_error";
418
- } else {
419
- // Your code here to handle a successful verification
420
- if ($pmpro_msgt != "pmpro_error")
421
- $pmpro_msg = "All good!";
422
- }
423
- } else {
424
- if ($pmpro_msgt != "pmpro_error")
425
- $pmpro_msg = "All good!";
426
- }
427
-
428
- //no errors yet
429
- if ($pmpro_msgt != "pmpro_error") {
430
- do_action('pmpro_checkout_before_processing');
431
-
432
- //process checkout if required
433
- if ($pmpro_requirebilling) {
434
- $morder = new MemberOrder();
435
- $morder->membership_id = $pmpro_level->id;
436
- $morder->membership_name = $pmpro_level->name;
437
- $morder->discount_code = $discount_code;
438
- $morder->InitialPayment = $pmpro_level->initial_payment;
439
- $morder->PaymentAmount = $pmpro_level->billing_amount;
440
- $morder->ProfileStartDate = date("Y-m-d", current_time("timestamp")) . "T0:0:0";
441
- $morder->BillingPeriod = $pmpro_level->cycle_period;
442
- $morder->BillingFrequency = $pmpro_level->cycle_number;
443
-
444
- if ($pmpro_level->billing_limit)
445
- $morder->TotalBillingCycles = $pmpro_level->billing_limit;
446
-
447
- if (pmpro_isLevelTrial($pmpro_level)) {
448
- $morder->TrialBillingPeriod = $pmpro_level->cycle_period;
449
- $morder->TrialBillingFrequency = $pmpro_level->cycle_number;
450
- $morder->TrialBillingCycles = $pmpro_level->trial_limit;
451
- $morder->TrialAmount = $pmpro_level->trial_amount;
452
- }
453
-
454
- //credit card values
455
- $morder->cardtype = $CardType;
456
- $morder->accountnumber = $AccountNumber;
457
- $morder->expirationmonth = $ExpirationMonth;
458
- $morder->expirationyear = $ExpirationYear;
459
- $morder->ExpirationDate = $ExpirationMonth . $ExpirationYear;
460
- $morder->ExpirationDate_YdashM = $ExpirationYear . "-" . $ExpirationMonth;
461
- $morder->CVV2 = $CVV;
462
-
463
- //not saving email in order table, but the sites need it
464
- $morder->Email = $bemail;
465
-
466
- //sometimes we need these split up
467
- $morder->FirstName = $bfirstname;
468
- $morder->LastName = $blastname;
469
- $morder->Address1 = $baddress1;
470
- $morder->Address2 = $baddress2;
471
-
472
- //other values
473
- $morder->billing = new stdClass();
474
- $morder->billing->name = $bfirstname . " " . $blastname;
475
- $morder->billing->street = trim($baddress1 . " " . $baddress2);
476
- $morder->billing->city = $bcity;
477
- $morder->billing->state = $bstate;
478
- $morder->billing->country = $bcountry;
479
- $morder->billing->zip = $bzipcode;
480
- $morder->billing->phone = $bphone;
481
-
482
- //$gateway = pmpro_getOption("gateway");
483
- $morder->gateway = $gateway;
484
- $morder->setGateway();
485
-
486
- //setup level var
487
- $morder->getMembershipLevel();
488
- $morder->membership_level = apply_filters("pmpro_checkout_level", $morder->membership_level);
489
-
490
- //tax
491
- $morder->subtotal = $morder->InitialPayment;
492
- $morder->getTax();
493
-
494
- //filter for order, since v2.0
495
- $morder = apply_filters("pmpro_checkout_order", $morder);
496
-
497
- $pmpro_processed = $morder->process();
498
-
499
- if (!empty($pmpro_processed))
500
- {
501
- $pmpro_msg = __("Payment accepted.", "pmpro");
502
- $pmpro_msgt = "pmpro_success";
503
- $pmpro_confirmed = true;
504
- }
505
- else
506
- {
507
- $pmpro_msg = $morder->error;
508
- if (empty($pmpro_msg))
509
- $pmpro_msg = __("Unknown error generating account. Please contact us to set up your membership.", "pmpro");
510
- $pmpro_msgt = "pmpro_error";
511
- }
512
-
513
- }
514
- else // !$pmpro_requirebilling
515
- {
516
- //must have been a free membership, continue
517
- $pmpro_confirmed = true;
518
- }
519
- }
520
- }
521
- } //endif ($pmpro_continue_registration)
522
- }
523
-
524
- //make sure we have at least an empty morder here to avoid a warning
525
- if (empty($morder))
526
- $morder = false;
527
-
528
- //Hook to check payment confirmation or replace it. If we get an array back, pull the values (morder) out
529
- $pmpro_confirmed = apply_filters('pmpro_checkout_confirmed', $pmpro_confirmed, $morder);
530
- if (is_array($pmpro_confirmed))
531
- extract($pmpro_confirmed);
532
-
533
- //if payment was confirmed create/update the user.
534
- if (!empty($pmpro_confirmed)) {
535
- //just in case this hasn't been set yet
536
- $submit = true;
537
-
538
- //do we need to create a user account?
539
- if (!$current_user->ID) {
540
- /*
541
- create user
542
- */
543
- if (version_compare($wp_version, "3.1") < 0)
544
- require_once( ABSPATH . WPINC . '/registration.php'); //need this for WP versions before 3.1
545
-
546
- //first name
547
- if (!empty($_REQUEST['first_name']))
548
- $first_name = $_REQUEST['first_name'];
549
- else
550
- $first_name = $bfirstname;
551
- //last name
552
- if (!empty($_REQUEST['last_name']))
553
- $last_name = $_REQUEST['last_name'];
554
- else
555
- $last_name = $blastname;
556
-
557
- //insert user
558
- $new_user_array = apply_filters('pmpro_checkout_new_user_array', array(
559
- "user_login" => $username,
560
- "user_pass" => $password,
561
- "user_email" => $bemail,
562
- "first_name" => $first_name,
563
- "last_name" => $last_name)
564
- );
565
-
566
- $user_id = apply_filters('pmpro_new_user', '', $new_user_array);
567
- if (!$user_id)
568
- $user_id = wp_insert_user($new_user_array);
569
-
570
- if (!$user_id || is_wp_error($user_id)) {
571
- $pmpro_msg = __("Your payment was accepted, but there was an error setting up your account. Please contact us.", "pmpro");
572
- $pmpro_msgt = "pmpro_error";
573
- } elseif ( apply_filters('pmpro_setup_new_user', true, $user_id, $new_user_array) ) {
574
-
575
- //check pmpro_wp_new_user_notification filter before sending the default WP email
576
- if (apply_filters("pmpro_wp_new_user_notification", true, $user_id, $pmpro_level->id))
577
- wp_new_user_notification($user_id, $new_user_array['user_pass']);
578
-
579
- $wpuser = get_userdata($user_id);
580
-
581
- //make the user a subscriber
582
- $wpuser->set_role(get_option('default_role', 'subscriber'));
583
-
584
- //okay, log them in to WP
585
- $creds = array();
586
- $creds['user_login'] = $new_user_array['user_login'];
587
- $creds['user_password'] = $new_user_array['user_pass'];
588
- $creds['remember'] = true;
589
- $user = wp_signon( $creds, false );
590
-
591
- //setting some cookies
592
- wp_set_current_user($user_id, $username);
593
- wp_set_auth_cookie($user_id, true, apply_filters('pmpro_checkout_signon_secure', (force_ssl_login() || force_ssl_admin())));
594
- }
595
- }
596
- else
597
- $user_id = $current_user->ID;
598
-
599
- if ($user_id && !is_wp_error($user_id))
600
- {
601
- do_action('pmpro_checkout_before_change_membership_level', $user_id, $morder);
602
-
603
- //calculate the end date
604
- if (!empty($pmpro_level->expiration_number)) {
605
- $enddate = "'" . date("Y-m-d", strtotime("+ " . $pmpro_level->expiration_number . " " . $pmpro_level->expiration_period, current_time("timestamp"))) . "'";
606
- } else {
607
- $enddate = "NULL";
608
- }
609
-
610
- //update membership_user table.
611
- if (!empty($discount_code) && !empty($use_discount_code))
612
- $discount_code_id = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_discount_codes WHERE code = '" . $discount_code . "' LIMIT 1");
613
- else
614
- $discount_code_id = "";
615
-
616
- //set the start date to NOW() but allow filters
617
- $startdate = apply_filters("pmpro_checkout_start_date", "'" . current_time("mysql") . "'", $user_id, $pmpro_level);
618
-
619
- $custom_level = array(
620
- 'user_id' => $user_id,
621
- 'membership_id' => $pmpro_level->id,
622
- 'code_id' => $discount_code_id,
623
- 'initial_payment' => $pmpro_level->initial_payment,
624
- 'billing_amount' => $pmpro_level->billing_amount,
625
- 'cycle_number' => $pmpro_level->cycle_number,
626
- 'cycle_period' => $pmpro_level->cycle_period,
627
- 'billing_limit' => $pmpro_level->billing_limit,
628
- 'trial_amount' => $pmpro_level->trial_amount,
629
- 'trial_limit' => $pmpro_level->trial_limit,
630
- 'startdate' => $startdate,
631
- 'enddate' => $enddate);
632
-
633
- if (pmpro_changeMembershipLevel($custom_level, $user_id, 'changed')) {
634
- //we're good
635
- //blank order for free levels
636
- if (empty($morder)) {
637
- $morder = new MemberOrder();
638
- $morder->InitialPayment = 0;
639
- $morder->Email = $bemail;
640
- $morder->gateway = "free";
641
- }
642
-
643
- //add an item to the history table, cancel old subscriptions
644
- if (!empty($morder)) {
645
- $morder->user_id = $user_id;
646
- $morder->membership_id = $pmpro_level->id;
647
- $morder->saveOrder();
648
- }
649
-
650
- //update the current user
651
- global $current_user;
652
- if (!$current_user->ID && $user->ID)
653
- $current_user = $user; //in case the user just signed up
654
- pmpro_set_current_user();
655
-
656
- //add discount code use
657
- if ($discount_code && $use_discount_code) {
658
- if (!empty($morder->id))
659
- $code_order_id = $morder->id;
660
- else
661
- $code_order_id = "";
662
-
663
- $wpdb->query("INSERT INTO $wpdb->pmpro_discount_codes_uses (code_id, user_id, order_id, timestamp) VALUES('" . $discount_code_id . "', '" . $user_id . "', '" . intval($code_order_id) . "', '" . current_time("mysql") . "')");
664
- }
665
-
666
- //save billing info ect, as user meta
667
- $meta_keys = array("pmpro_bfirstname", "pmpro_blastname", "pmpro_baddress1", "pmpro_baddress2", "pmpro_bcity", "pmpro_bstate", "pmpro_bzipcode", "pmpro_bcountry", "pmpro_bphone", "pmpro_bemail", "pmpro_CardType", "pmpro_AccountNumber", "pmpro_ExpirationMonth", "pmpro_ExpirationYear");
668
- $meta_values = array($bfirstname, $blastname, $baddress1, $baddress2, $bcity, $bstate, $bzipcode, $bcountry, $bphone, $bemail, $CardType, hideCardNumber($AccountNumber), $ExpirationMonth, $ExpirationYear);
669
- pmpro_replaceUserMeta($user_id, $meta_keys, $meta_values);
670
-
671
- //save first and last name fields
672
- if (!empty($bfirstname)) {
673
- $old_firstname = get_user_meta($user_id, "first_name", true);
674
- if (empty($old_firstname))
675
- update_user_meta($user_id, "first_name", $bfirstname);
676
- }
677
- if (!empty($blastname)) {
678
- $old_lastname = get_user_meta($user_id, "last_name", true);
679
- if (empty($old_lastname))
680
- update_user_meta($user_id, "last_name", $blastname);
681
- }
682
-
683
- //show the confirmation
684
- $ordersaved = true;
685
-
686
- //hook
687
- do_action("pmpro_after_checkout", $user_id, $morder); //added $morder param in v2.0
688
-
689
- //setup some values for the emails
690
- if (!empty($morder))
691
- $invoice = new MemberOrder($morder->id);
692
- else
693
- $invoice = NULL;
694
- $current_user->membership_level = $pmpro_level; //make sure they have the right level info
695
-
696
- //send email to member
697
- $pmproemail = new PMProEmail();
698
- $pmproemail->sendCheckoutEmail($current_user, $invoice);
699
-
700
- //send email to admin
701
- $pmproemail = new PMProEmail();
702
- $pmproemail->sendCheckoutAdminEmail($current_user, $invoice);
703
-
704
- //redirect to confirmation
705
- $rurl = pmpro_url("confirmation", "?level=" . $pmpro_level->id);
706
- $rurl = apply_filters("pmpro_confirmation_url", $rurl, $user_id, $pmpro_level);
707
- wp_redirect($rurl);
708
- exit;
709
- } else {
710
- //uh oh. we charged them then the membership creation failed
711
- if (isset($morder) && $morder->cancel()) {
712
- $pmpro_msg = __("IMPORTANT: Something went wrong during membership creation. Your credit card authorized, but we cancelled the order immediately. You should not try to submit this form again. Please contact the site owner to fix this issue.", "pmpro");
713
- $morder = NULL;
714
- } else {
715
- $pmpro_msg = __("IMPORTANT: Something went wrong during membership creation. Your credit card was charged, but we couldn't assign your membership. You should not submit this form again. Please contact the site owner to fix this issue.", "pmpro");
716
- }
717
- }
718
- }
719
- }
720
-
721
- //default values
722
- if (empty($submit)) {
723
- //show message if the payment gateway is not setup yet
724
- if ($pmpro_requirebilling && !pmpro_getOption("gateway", true)) {
725
- if (pmpro_isAdmin())
726
- $pmpro_msg = sprintf(__('You must <a href="%s">set up a Payment Gateway</a> before any payments will be processed.', 'pmpro'), get_admin_url(NULL, '/admin.php?page=pmpro-membershiplevels&view=payment'));
727
- else
728
- $pmpro_msg = __("A Payment Gateway must be set up before any payments will be processed.", "pmpro");
729
- $pmpro_msgt = "";
730
- }
731
-
732
- //default values from DB
733
- if (!empty($current_user->ID)) {
734
- $bfirstname = get_user_meta($current_user->ID, "pmpro_bfirstname", true);
735
- $blastname = get_user_meta($current_user->ID, "pmpro_blastname", true);
736
- $baddress1 = get_user_meta($current_user->ID, "pmpro_baddress1", true);
737
- $baddress2 = get_user_meta($current_user->ID, "pmpro_baddress2", true);
738
- $bcity = get_user_meta($current_user->ID, "pmpro_bcity", true);
739
- $bstate = get_user_meta($current_user->ID, "pmpro_bstate", true);
740
- $bzipcode = get_user_meta($current_user->ID, "pmpro_bzipcode", true);
741
- $bcountry = get_user_meta($current_user->ID, "pmpro_bcountry", true);
742
- $bphone = get_user_meta($current_user->ID, "pmpro_bphone", true);
743
- $bemail = get_user_meta($current_user->ID, "pmpro_bemail", true);
744
- $bconfirmemail = $bemail; //as of 1.7.5, just setting to bemail
745
- $CardType = get_user_meta($current_user->ID, "pmpro_CardType", true);
746
- //$AccountNumber = hideCardNumber(get_user_meta($current_user->ID, "pmpro_AccountNumber", true), false);
747
- $ExpirationMonth = get_user_meta($current_user->ID, "pmpro_ExpirationMonth", true);
748
- $ExpirationYear = get_user_meta($current_user->ID, "pmpro_ExpirationYear", true);
749
- }
750
- }
751
-
752
- //clear out XXXX numbers (e.g. with Stripe)
753
- if (!empty($AccountNumber) && strpos($AccountNumber, "XXXX") === 0)
754
- $AccountNumber = "";
 
 
1
+ <?php
2
+ global $post, $gateway, $wpdb, $besecure, $discount_code, $discount_code_id, $pmpro_level, $pmpro_levels, $pmpro_msg, $pmpro_msgt, $pmpro_review, $skip_account_fields, $pmpro_paypal_token, $pmpro_show_discount_code, $pmpro_error_fields, $pmpro_required_billing_fields, $pmpro_required_user_fields, $wp_version, $current_user;
3
+
4
+ //make sure we know current user's membership level
5
+ if ($current_user->ID)
6
+ $current_user->membership_level = pmpro_getMembershipLevelForUser($current_user->ID);
7
+
8
+ //this var stores fields with errors so we can make them red on the frontend
9
+ $pmpro_error_fields = array();
10
+
11
+ //blank array for required fields, set below
12
+ $pmpro_required_billing_fields = array();
13
+ $pmpro_required_user_fields = array();
14
+
15
+ //was a gateway passed?
16
+ if (!empty($_REQUEST['gateway']))
17
+ $gateway = $_REQUEST['gateway'];
18
+ elseif (!empty($_REQUEST['review']))
19
+ $gateway = "paypalexpress";
20
+ else
21
+ $gateway = pmpro_getOption("gateway");
22
+
23
+ //set valid gateways - the active gateway in the settings and any gateway added through the filter will be allowed
24
+ if (pmpro_getOption("gateway", true) == "paypal")
25
+ $valid_gateways = apply_filters("pmpro_valid_gateways", array("paypal", "paypalexpress"));
26
+ else
27
+ $valid_gateways = apply_filters("pmpro_valid_gateways", array(pmpro_getOption("gateway", true)));
28
+
29
+ //let's add an error now, if an invalid gateway is set
30
+ if (!in_array($gateway, $valid_gateways))
31
+ {
32
+ $pmpro_msg = __("Invalid gateway.", 'pmpro');
33
+ $pmpro_msgt = "pmpro_error";
34
+ }
35
+
36
+ //what level are they purchasing? (discount code passed)
37
+ if (!empty($_REQUEST['level']) && !empty($_REQUEST['discount_code'])) {
38
+ $discount_code = preg_replace("/[^A-Za-z0-9\-]/", "", $_REQUEST['discount_code']);
39
+ $discount_code_id = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_discount_codes WHERE code = '" . $discount_code . "' LIMIT 1");
40
+
41
+ //check code
42
+ $code_check = pmpro_checkDiscountCode($discount_code, (int)$_REQUEST['level'], true);
43
+ if ($code_check[0] == false) {
44
+ //error
45
+ $pmpro_msg = $code_check[1];
46
+ $pmpro_msgt = "pmpro_error";
47
+
48
+ //don't use this code
49
+ $use_discount_code = false;
50
+ } else {
51
+ $sqlQuery = "SELECT l.id, cl.*, l.name, l.description, l.allow_signups FROM $wpdb->pmpro_discount_codes_levels cl LEFT JOIN $wpdb->pmpro_membership_levels l ON cl.level_id = l.id LEFT JOIN $wpdb->pmpro_discount_codes dc ON dc.id = cl.code_id WHERE dc.code = '" . $discount_code . "' AND cl.level_id = '" . (int)$_REQUEST['level'] . "' LIMIT 1";
52
+ $pmpro_level = $wpdb->get_row($sqlQuery);
53
+
54
+ //if the discount code doesn't adjust the level, let's just get the straight level
55
+ if (empty($pmpro_level))
56
+ $pmpro_level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . (int)$_REQUEST['level'] . "' LIMIT 1");
57
+
58
+ //filter adjustments to the level
59
+ $pmpro_level->code_id = $discount_code_id;
60
+ $pmpro_level = apply_filters("pmpro_discount_code_level", $pmpro_level, $discount_code_id);
61
+
62
+ $use_discount_code = true;
63
+ }
64
+ }
65
+
66
+ //what level are they purchasing? (no discount code)
67
+ if (empty($pmpro_level) && !empty($_REQUEST['level'])) {
68
+ $pmpro_level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . esc_sql($_REQUEST['level']) . "' AND allow_signups = 1 LIMIT 1");
69
+ } elseif (empty($pmpro_level)) {
70
+ //check if a level is defined in custom fields
71
+ $default_level = get_post_meta($post->ID, "pmpro_default_level", true);
72
+ if (!empty($default_level))
73
+ {
74
+ $pmpro_level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . esc_sql($default_level) . "' AND allow_signups = 1 LIMIT 1");
75
+ }
76
+ }
77
+
78
+ //filter the level (for upgrades, etc)
79
+ $pmpro_level = apply_filters("pmpro_checkout_level", $pmpro_level);
80
+
81
+ if (empty($pmpro_level->id))
82
+ {
83
+ wp_redirect(pmpro_url("levels"));
84
+ exit(0);
85
+ }
86
+
87
+ //enqueue some scripts
88
+ wp_enqueue_script('jquery.creditCardValidator', plugins_url('/js/jquery.creditCardValidator.js' , dirname(__FILE__ )), array( 'jquery' ));
89
+
90
+ global $wpdb, $current_user, $pmpro_requirebilling;
91
+ //unless we're submitting a form, let's try to figure out if https should be used
92
+
93
+ if (!pmpro_isLevelFree($pmpro_level)) {
94
+ //require billing and ssl
95
+ $pagetitle = __("Checkout: Payment Information", 'pmpro');
96
+ $pmpro_requirebilling = true;
97
+ $besecure = pmpro_getOption("use_ssl");
98
+ } else {
99
+ //no payment so we don't need ssl
100
+ $pagetitle = __("Set Up Your Account", 'pmpro');
101
+ $pmpro_requirebilling = false;
102
+ $besecure = false;
103
+ }
104
+
105
+ //in case a discount code was used or something else made the level free, but we're already over ssl
106
+ if (!$besecure && !empty($_REQUEST['submit-checkout']) && is_ssl())
107
+ $besecure = true; //be secure anyway since we're already checking out
108
+
109
+ //action to run extra code for gateways/etc
110
+ do_action('pmpro_checkout_preheader');
111
+
112
+ //get all levels in case we need them
113
+ global $pmpro_levels;
114
+ $pmpro_levels = pmpro_getAllLevels();
115
+
116
+ //should we show the discount code field?
117
+ if ($wpdb->get_var("SELECT id FROM $wpdb->pmpro_discount_codes LIMIT 1"))
118
+ $pmpro_show_discount_code = true;
119
+ else
120
+ $pmpro_show_discount_code = false;
121
+ $pmpro_show_discount_code = apply_filters("pmpro_show_discount_code", $pmpro_show_discount_code);
122
+
123
+ //by default we show the account fields if the user isn't logged in
124
+ if ($current_user->ID) {
125
+ $skip_account_fields = true;
126
+ } else {
127
+ $skip_account_fields = false;
128
+ }
129
+ //in case people want to have an account created automatically
130
+ $skip_account_fields = apply_filters("pmpro_skip_account_fields", $skip_account_fields, $current_user);
131
+
132
+ //some options
133
+ global $tospage;
134
+ $tospage = pmpro_getOption("tospage");
135
+ if ($tospage)
136
+ $tospage = get_post($tospage);
137
+
138
+ //load em up (other fields)
139
+ global $username, $password, $password2, $bfirstname, $blastname, $baddress1, $baddress2, $bcity, $bstate, $bzipcode, $bcountry, $bphone, $bemail, $bconfirmemail, $CardType, $AccountNumber, $ExpirationMonth, $ExpirationYear;
140
+
141
+ if (isset($_REQUEST['order_id']))
142
+ $order_id = intval($_REQUEST['order_id']);
143
+ else
144
+ $order_id = "";
145
+ if (isset($_REQUEST['bfirstname']))
146
+ $bfirstname = sanitize_text_field(stripslashes($_REQUEST['bfirstname']));
147
+ else
148
+ $bfirstname = "";
149
+ if (isset($_REQUEST['blastname']))
150
+ $blastname = sanitize_text_field(stripslashes($_REQUEST['blastname']));
151
+ else
152
+ $blastname = "";
153
+ if (isset($_REQUEST['fullname']))
154
+ $fullname = $_REQUEST['fullname']; //honeypot for spammers
155
+ if (isset($_REQUEST['baddress1']))
156
+ $baddress1 = sanitize_text_field(stripslashes($_REQUEST['baddress1']));
157
+ else
158
+ $baddress1 = "";
159
+ if (isset($_REQUEST['baddress2']))
160
+ $baddress2 = sanitize_text_field(stripslashes($_REQUEST['baddress2']));
161
+ else
162
+ $baddress2 = "";
163
+ if (isset($_REQUEST['bcity']))
164
+ $bcity = sanitize_text_field(stripslashes($_REQUEST['bcity']));
165
+ else
166
+ $bcity = "";
167
+
168
+ if (isset($_REQUEST['bstate']))
169
+ $bstate = sanitize_text_field(stripslashes($_REQUEST['bstate']));
170
+ else
171
+ $bstate = "";
172
+
173
+ //convert long state names to abbreviations
174
+ if (!empty($bstate))
175
+ {
176
+ global $pmpro_states;
177
+ foreach($pmpro_states as $abbr => $state)
178
+ {
179
+ if ($bstate == $state)
180
+ {
181
+ $bstate = $abbr;
182
+ break;
183
+ }
184
+ }
185
+ }
186
+
187
+ if (isset($_REQUEST['bzipcode']))
188
+ $bzipcode = sanitize_text_field(stripslashes($_REQUEST['bzipcode']));
189
+ else
190
+ $bzipcode = "";
191
+ if (isset($_REQUEST['bcountry']))
192
+ $bcountry = sanitize_text_field(stripslashes($_REQUEST['bcountry']));
193
+ else
194
+ $bcountry = "";
195
+ if (isset($_REQUEST['bphone']))
196
+ $bphone = sanitize_text_field(stripslashes($_REQUEST['bphone']));
197
+ else
198
+ $bphone = "";
199
+ if (isset($_REQUEST['bemail']))
200
+ $bemail = sanitize_email(stripslashes($_REQUEST['bemail']));
201
+ else
202
+ $bemail = "";
203
+ if (isset($_REQUEST['bconfirmemail_copy']))
204
+ $bconfirmemail = $bemail;
205
+ elseif (isset($_REQUEST['bconfirmemail']))
206
+ $bconfirmemail = sanitize_email(stripslashes($_REQUEST['bconfirmemail']));
207
+ else
208
+ $bconfirmemail = "";
209
+
210
+ if (isset($_REQUEST['CardType']) && !empty($_REQUEST['AccountNumber']))
211
+ $CardType = sanitize_text_field($_REQUEST['CardType']);
212
+ else
213
+ $CardType = "";
214
+ if (isset($_REQUEST['AccountNumber']))
215
+ $AccountNumber = sanitize_text_field($_REQUEST['AccountNumber']);
216
+ else
217
+ $AccountNumber = "";
218
+
219
+ if (isset($_REQUEST['ExpirationMonth']))
220
+ $ExpirationMonth = sanitize_text_field($_REQUEST['ExpirationMonth']);
221
+ else
222
+ $ExpirationMonth = "";
223
+ if (isset($_REQUEST['ExpirationYear']))
224
+ $ExpirationYear = sanitize_text_field($_REQUEST['ExpirationYear']);
225
+ else
226
+ $ExpirationYear = "";
227
+ if (isset($_REQUEST['CVV']))
228
+ $CVV = sanitize_text_field($_REQUEST['CVV']);
229
+ else
230
+ $CVV = "";
231
+
232
+ if (isset($_REQUEST['discount_code']))
233
+ $discount_code = sanitize_text_field($_REQUEST['discount_code']);
234
+ else
235
+ $discount_code = "";
236
+ if (isset($_REQUEST['username']))
237
+ $username = sanitize_user($_REQUEST['username']);
238
+ else
239
+ $username = "";
240
+ if (isset($_REQUEST['password']))
241
+ $password = $_REQUEST['password'];
242
+ else
243
+ $password = "";
244
+ if (isset($_REQUEST['password2_copy']))
245
+ $password2 = $password;
246
+ elseif (isset($_REQUEST['password2']))
247
+ $password2 = $_REQUEST['password2'];
248
+ else
249
+ $password2 = "";
250
+ if (isset($_REQUEST['tos']))
251
+ $tos = intval($_REQUEST['tos']);
252
+ else
253
+ $tos = "";
254
+
255
+ //_x stuff in case they clicked on the image button with their mouse
256
+ if (isset($_REQUEST['submit-checkout']))
257
+ $submit = $_REQUEST['submit-checkout'];
258
+ if (empty($submit) && isset($_REQUEST['submit-checkout_x']) )
259
+ $submit = $_REQUEST['submit-checkout_x'];
260
+ if (isset($submit) && $submit === "0")
261
+ $submit = true;
262
+ elseif (!isset($submit))
263
+ $submit = false;
264
+
265
+ //require fields
266
+ $pmpro_required_billing_fields = array(
267
+ "bfirstname" => $bfirstname,
268
+ "blastname" => $blastname,
269
+ "baddress1" => $baddress1,
270
+ "bcity" => $bcity,
271
+ "bstate" => $bstate,
272
+ "bzipcode" => $bzipcode,
273
+ "bphone" => $bphone,
274
+ "bemail" => $bemail,
275
+ "bcountry" => $bcountry,
276
+ "CardType" => $CardType,
277
+ "AccountNumber" => $AccountNumber,
278
+ "ExpirationMonth" => $ExpirationMonth,
279
+ "ExpirationYear" => $ExpirationYear,
280
+ "CVV" => $CVV
281
+ );
282
+ $pmpro_required_billing_fields = apply_filters("pmpro_required_billing_fields", $pmpro_required_billing_fields);
283
+ $pmpro_required_user_fields = array(
284
+ "username" => $username,
285
+ "password" => $password,
286
+ "password2" => $password2,
287
+ "bemail" => $bemail,
288
+ "bconfirmemail" => $bconfirmemail
289
+ );
290
+ $pmpro_required_user_fields = apply_filters("pmpro_required_user_fields", $pmpro_required_user_fields);
291
+
292
+ //pmpro_confirmed is set to true later if payment goes through
293
+ $pmpro_confirmed = false;
294
+
295
+ //check their fields if they clicked continue
296
+ if ($submit && $pmpro_msgt != "pmpro_error") {
297
+
298
+ //make sure javascript is ok
299
+ if (apply_filters("pmpro_require_javascript_for_checkout", true) && !empty($_REQUEST['checkjavascript']) && empty($_REQUEST['javascriptok'])) {
300
+ pmpro_setMessage(__("There are JavaScript errors on the page. Please contact the webmaster.", "pmpro"), "pmpro_error");
301
+ }
302
+
303
+ //if we're skipping the account fields and there is no user, we need to create a username and password
304
+ if ($skip_account_fields && !$current_user->ID) {
305
+ $username = pmpro_generateUsername($bfirstname, $blastname, $bemail);
306
+ if (empty($username))
307
+ $username = pmpro_getDiscountCode();
308
+ $password = pmpro_getDiscountCode() . pmpro_getDiscountCode(); //using two random discount codes
309
+ $password2 = $password;
310
+ }
311
+
312
+ //check billing fields
313
+ if ($pmpro_requirebilling) {
314
+ //filter
315
+ foreach($pmpro_required_billing_fields as $key => $field) {
316
+ if (!$field) {
317
+ $pmpro_error_fields[] = $key;
318
+ }
319
+ }
320
+ }
321
+
322
+ //check user fields
323
+ if (empty($current_user->ID)) {
324
+ foreach($pmpro_required_user_fields as $key => $field) {
325
+ if (!$field) {
326
+ $pmpro_error_fields[] = $key;
327
+ }
328
+ }
329
+ }
330
+
331
+ if (!empty($pmpro_error_fields)) {
332
+ pmpro_setMessage(__("Please complete all required fields.", "pmpro"), "pmpro_error");
333
+ }
334
+ if (!empty($password) && $password != $password2) {
335
+ pmpro_setMessage(__("Your passwords do not match. Please try again.", "pmpro"), "pmpro_error");
336
+ $pmpro_error_fields[] = "password";
337
+ $pmpro_error_fields[] = "password2";
338
+ }
339
+ if (!empty($bemail) && $bemail != $bconfirmemail) {
340
+ pmpro_setMessage(__("Your email addresses do not match. Please try again.", "pmpro"), "pmpro_error");
341
+ $pmpro_error_fields[] = "bemail";
342
+ $pmpro_error_fields[] = "bconfirmemail";
343
+ }
344
+ if (!empty($bemail) && !is_email($bemail)) {
345
+ pmpro_setMessage(__("The email address entered is in an invalid format. Please try again.", "pmpro"), "pmpro_error");
346
+ $pmpro_error_fields[] = "bemail";
347
+ $pmpro_error_fields[] = "bconfirmemail";
348
+ }
349
+ if (!empty($tospage) && empty($tos)) {
350
+ pmpro_setMessage(sprintf(__("Please check the box to agree to the %s.", "pmpro"), $tospage->post_title), "pmpro_error");
351
+ $pmpro_error_fields[] = "tospage";
352
+ }
353
+ if (!in_array($gateway, $valid_gateways)) {
354
+ pmpro_setMessage(__("Invalid gateway.", "pmpro"), "pmpro_error");
355
+ }
356
+ if (!empty($fullname)) {
357
+ pmpro_setMessage(__("Are you a spammer?", "pmpro"), "pmpro_error");
358
+ }
359
+
360
+ if ($pmpro_msgt == "pmpro_error")
361
+ $pmpro_continue_registration = false;
362
+ else
363
+ $pmpro_continue_registration = true;
364
+ $pmpro_continue_registration = apply_filters("pmpro_registration_checks", $pmpro_continue_registration);
365
+
366
+ if ($pmpro_continue_registration) {
367
+ //if creating a new user, check that the email and username are available
368
+ if (empty($current_user->ID)) {
369
+ $oldusername = $wpdb->get_var("SELECT user_login FROM $wpdb->users WHERE user_login = '" . esc_sql($username) . "' LIMIT 1");
370
+ $oldemail = $wpdb->get_var("SELECT user_email FROM $wpdb->users WHERE user_email = '" . esc_sql($bemail) . "' LIMIT 1");
371
+
372
+ //this hook can be used to allow multiple accounts with the same email address
373
+ $oldemail = apply_filters("pmpro_checkout_oldemail", $oldemail);
374
+ }
375
+
376
+ if (!empty($oldusername)) {
377
+ pmpro_setMessage(__("That username is already taken. Please try another.", "pmpro"), "pmpro_error");
378
+ $pmpro_error_fields[] = "username";
379
+ }
380
+
381
+ if (!empty($oldemail)) {
382
+ pmpro_setMessage(__("That email address is already taken. Please try another.", "pmpro"), "pmpro_error");
383
+ $pmpro_error_fields[] = "bemail";
384
+ $pmpro_error_fields[] = "bconfirmemail";
385
+ }
386
+
387
+ //only continue if there are no other errors yet
388
+ if ($pmpro_msgt != "pmpro_error") {
389
+ //check recaptcha first
390
+ global $recaptcha;
391
+ if (!$skip_account_fields && ($recaptcha == 2 || ($recaptcha == 1 && pmpro_isLevelFree($pmpro_level)))) {
392
+ global $recaptcha_privatekey;
393
+
394
+ if(isset($_POST["recaptcha_challenge_field"]))
395
+ {
396
+ //using older recaptcha lib
397
+ $resp = recaptcha_check_answer($recaptcha_privatekey,
398
+ $_SERVER["REMOTE_ADDR"],
399
+ $_POST["recaptcha_challenge_field"],
400
+ $_POST["recaptcha_response_field"]);
401
+
402
+ $recaptcha_valid = $resp->is_valid;
403
+ $recaptcha_errors = $resp->error;
404
+ }
405
+ else
406
+ {
407
+ //using newer recaptcha lib
408
+ $reCaptcha = new pmpro_ReCaptcha($recaptcha_privatekey);
409
+ $resp = $reCaptcha->verifyResponse($_SERVER["REMOTE_ADDR"], $_POST["g-recaptcha-response"]);
410
+
411
+ $recaptcha_valid = $resp->success;
412
+ $recaptcha_errors = $resp->errorCodes;
413
+ }
414
+
415
+ if (!$recaptcha_valid) {
416
+ $pmpro_msg = sprintf(__("reCAPTCHA failed. (%s) Please try again.", "pmpro"), $recaptcha_errors);
417
+ $pmpro_msgt = "pmpro_error";
418
+ } else {
419
+ // Your code here to handle a successful verification
420
+ if ($pmpro_msgt != "pmpro_error")
421
+ $pmpro_msg = "All good!";
422
+ }
423
+ } else {
424
+ if ($pmpro_msgt != "pmpro_error")
425
+ $pmpro_msg = "All good!";
426
+ }
427
+
428
+ //no errors yet
429
+ if ($pmpro_msgt != "pmpro_error") {
430
+ do_action('pmpro_checkout_before_processing');
431
+
432
+ //process checkout if required
433
+ if ($pmpro_requirebilling) {
434
+ $morder = new MemberOrder();
435
+ $morder->membership_id = $pmpro_level->id;
436
+ $morder->membership_name = $pmpro_level->name;
437
+ $morder->discount_code = $discount_code;
438
+ $morder->InitialPayment = $pmpro_level->initial_payment;
439
+ $morder->PaymentAmount = $pmpro_level->billing_amount;
440
+ $morder->ProfileStartDate = date("Y-m-d", current_time("timestamp")) . "T0:0:0";
441
+ $morder->BillingPeriod = $pmpro_level->cycle_period;
442
+ $morder->BillingFrequency = $pmpro_level->cycle_number;
443
+
444
+ if ($pmpro_level->billing_limit)
445
+ $morder->TotalBillingCycles = $pmpro_level->billing_limit;
446
+
447
+ if (pmpro_isLevelTrial($pmpro_level)) {
448
+ $morder->TrialBillingPeriod = $pmpro_level->cycle_period;
449
+ $morder->TrialBillingFrequency = $pmpro_level->cycle_number;
450
+ $morder->TrialBillingCycles = $pmpro_level->trial_limit;
451
+ $morder->TrialAmount = $pmpro_level->trial_amount;
452
+ }
453
+
454
+ //credit card values
455
+ $morder->cardtype = $CardType;
456
+ $morder->accountnumber = $AccountNumber;
457
+ $morder->expirationmonth = $ExpirationMonth;
458
+ $morder->expirationyear = $ExpirationYear;
459
+ $morder->ExpirationDate = $ExpirationMonth . $ExpirationYear;
460
+ $morder->ExpirationDate_YdashM = $ExpirationYear . "-" . $ExpirationMonth;
461
+ $morder->CVV2 = $CVV;
462
+
463
+ //not saving email in order table, but the sites need it
464
+ $morder->Email = $bemail;
465
+
466
+ //sometimes we need these split up
467
+ $morder->FirstName = $bfirstname;
468
+ $morder->LastName = $blastname;
469
+ $morder->Address1 = $baddress1;
470
+ $morder->Address2 = $baddress2;
471
+
472
+ //other values
473
+ $morder->billing = new stdClass();
474
+ $morder->billing->name = $bfirstname . " " . $blastname;
475
+ $morder->billing->street = trim($baddress1 . " " . $baddress2);
476
+ $morder->billing->city = $bcity;
477
+ $morder->billing->state = $bstate;
478
+ $morder->billing->country = $bcountry;
479
+ $morder->billing->zip = $bzipcode;
480
+ $morder->billing->phone = $bphone;
481
+
482
+ //$gateway = pmpro_getOption("gateway");
483
+ $morder->gateway = $gateway;
484
+ $morder->setGateway();
485
+
486
+ //setup level var
487
+ $morder->getMembershipLevel();
488
+ $morder->membership_level = apply_filters("pmpro_checkout_level", $morder->membership_level);
489
+
490
+ //tax
491
+ $morder->subtotal = $morder->InitialPayment;
492
+ $morder->getTax();
493
+
494
+ //filter for order, since v1.8
495
+ $morder = apply_filters("pmpro_checkout_order", $morder);
496
+
497
+ $pmpro_processed = $morder->process();
498
+
499
+ if (!empty($pmpro_processed))
500
+ {
501
+ $pmpro_msg = __("Payment accepted.", "pmpro");
502
+ $pmpro_msgt = "pmpro_success";
503
+ $pmpro_confirmed = true;
504
+ }
505
+ else
506
+ {
507
+ $pmpro_msg = $morder->error;
508
+ if (empty($pmpro_msg))
509
+ $pmpro_msg = __("Unknown error generating account. Please contact us to set up your membership.", "pmpro");
510
+ $pmpro_msgt = "pmpro_error";
511
+ }
512
+
513
+ }
514
+ else // !$pmpro_requirebilling
515
+ {
516
+ //must have been a free membership, continue
517
+ $pmpro_confirmed = true;
518
+ }
519
+ }
520
+ }
521
+ } //endif ($pmpro_continue_registration)
522
+ }
523
+
524
+ //make sure we have at least an empty morder here to avoid a warning
525
+ if (empty($morder))
526
+ $morder = false;
527
+
528
+ //Hook to check payment confirmation or replace it. If we get an array back, pull the values (morder) out
529
+ $pmpro_confirmed = apply_filters('pmpro_checkout_confirmed', $pmpro_confirmed, $morder);
530
+ if (is_array($pmpro_confirmed))
531
+ extract($pmpro_confirmed);
532
+
533
+ //if payment was confirmed create/update the user.
534
+ if (!empty($pmpro_confirmed)) {
535
+ //just in case this hasn't been set yet
536
+ $submit = true;
537
+
538
+ //do we need to create a user account?
539
+ if (!$current_user->ID) {
540
+ /*
541
+ create user
542
+ */
543
+ if (version_compare($wp_version, "3.1") < 0)
544
+ require_once( ABSPATH . WPINC . '/registration.php'); //need this for WP versions before 3.1
545
+
546
+ //first name
547
+ if (!empty($_REQUEST['first_name']))
548
+ $first_name = $_REQUEST['first_name'];
549
+ else
550
+ $first_name = $bfirstname;
551
+ //last name
552
+ if (!empty($_REQUEST['last_name']))
553
+ $last_name = $_REQUEST['last_name'];
554
+ else
555
+ $last_name = $blastname;
556
+
557
+ //insert user
558
+ $new_user_array = apply_filters('pmpro_checkout_new_user_array', array(
559
+ "user_login" => $username,
560
+ "user_pass" => $password,
561
+ "user_email" => $bemail,
562
+ "first_name" => $first_name,
563
+ "last_name" => $last_name)
564
+ );
565
+
566
+ $user_id = apply_filters('pmpro_new_user', '', $new_user_array);
567
+ if (!$user_id)
568
+ $user_id = wp_insert_user($new_user_array);
569
+
570
+ if (!$user_id || is_wp_error($user_id)) {
571
+ $pmpro_msg = __("Your payment was accepted, but there was an error setting up your account. Please contact us.", "pmpro");
572
+ $pmpro_msgt = "pmpro_error";
573
+ } elseif (apply_filters('pmpro_setup_new_user', true, $user_id, $new_user_array, $pmpro_level)) {
574
+
575
+ //check pmpro_wp_new_user_notification filter before sending the default WP email
576
+ if (apply_filters("pmpro_wp_new_user_notification", true, $user_id, $pmpro_level->id))
577
+ wp_new_user_notification($user_id, $new_user_array['user_pass']);
578
+
579
+ $wpuser = get_userdata($user_id);
580
+
581
+ //make the user a subscriber
582
+ $wpuser->set_role(get_option('default_role', 'subscriber'));
583
+
584
+ //okay, log them in to WP
585
+ $creds = array();
586
+ $creds['user_login'] = $new_user_array['user_login'];
587
+ $creds['user_password'] = $new_user_array['user_pass'];
588
+ $creds['remember'] = true;
589
+ $user = wp_signon( $creds, false );
590
+
591
+ //setting some cookies
592
+ wp_set_current_user($user_id, $username);
593
+ wp_set_auth_cookie($user_id, true, apply_filters('pmpro_checkout_signon_secure', (force_ssl_login() || force_ssl_admin())));
594
+ }
595
+ }
596
+ else
597
+ $user_id = $current_user->ID;
598
+
599
+ if ($user_id && !is_wp_error($user_id))
600
+ {
601
+ do_action('pmpro_checkout_before_change_membership_level', $user_id, $morder);
602
+
603
+ //calculate the end date
604
+ if (!empty($pmpro_level->expiration_number)) {
605
+ $enddate = "'" . date("Y-m-d", strtotime("+ " . $pmpro_level->expiration_number . " " . $pmpro_level->expiration_period, current_time("timestamp"))) . "'";
606
+ } else {
607
+ $enddate = "NULL";
608
+ }
609
+
610
+ //update membership_user table.
611
+ if (!empty($discount_code) && !empty($use_discount_code))
612
+ $discount_code_id = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_discount_codes WHERE code = '" . $discount_code . "' LIMIT 1");
613
+ else
614
+ $discount_code_id = "";
615
+
616
+ //set the start date to NOW() but allow filters
617
+ $startdate = apply_filters("pmpro_checkout_start_date", "'" . current_time("mysql") . "'", $user_id, $pmpro_level);
618
+
619
+ $custom_level = array(
620
+ 'user_id' => $user_id,
621
+ 'membership_id' => $pmpro_level->id,
622
+ 'code_id' => $discount_code_id,
623
+ 'initial_payment' => $pmpro_level->initial_payment,
624
+ 'billing_amount' => $pmpro_level->billing_amount,
625
+ 'cycle_number' => $pmpro_level->cycle_number,
626
+ 'cycle_period' => $pmpro_level->cycle_period,
627
+ 'billing_limit' => $pmpro_level->billing_limit,
628
+ 'trial_amount' => $pmpro_level->trial_amount,
629
+ 'trial_limit' => $pmpro_level->trial_limit,
630
+ 'startdate' => $startdate,
631
+ 'enddate' => $enddate);
632
+
633
+ if (pmpro_changeMembershipLevel($custom_level, $user_id, 'changed')) {
634
+ //we're good
635
+ //blank order for free levels
636
+ if (empty($morder)) {
637
+ $morder = new MemberOrder();
638
+ $morder->InitialPayment = 0;
639
+ $morder->Email = $bemail;
640
+ $morder->gateway = "free";
641
+
642
+ $morder = apply_filters("pmpro_checkout_order_free", $morder);
643
+ }
644
+
645
+ //add an item to the history table, cancel old subscriptions
646
+ if (!empty($morder)) {
647
+ $morder->user_id = $user_id;
648
+ $morder->membership_id = $pmpro_level->id;
649
+ $morder->saveOrder();
650
+ }
651
+
652
+ //update the current user
653
+ global $current_user;
654
+ if (!$current_user->ID && $user->ID)
655
+ $current_user = $user; //in case the user just signed up
656
+ pmpro_set_current_user();
657
+
658
+ //add discount code use
659
+ if ($discount_code && $use_discount_code) {
660
+ if (!empty($morder->id))
661
+ $code_order_id = $morder->id;
662
+ else
663
+ $code_order_id = "";
664
+
665
+ $wpdb->query("INSERT INTO $wpdb->pmpro_discount_codes_uses (code_id, user_id, order_id, timestamp) VALUES('" . $discount_code_id . "', '" . $user_id . "', '" . intval($code_order_id) . "', '" . current_time("mysql") . "')");
666
+ }
667
+
668
+ //save billing info ect, as user meta
669
+ $meta_keys = array("pmpro_bfirstname", "pmpro_blastname", "pmpro_baddress1", "pmpro_baddress2", "pmpro_bcity", "pmpro_bstate", "pmpro_bzipcode", "pmpro_bcountry", "pmpro_bphone", "pmpro_bemail", "pmpro_CardType", "pmpro_AccountNumber", "pmpro_ExpirationMonth", "pmpro_ExpirationYear");
670
+ $meta_values = array($bfirstname, $blastname, $baddress1, $baddress2, $bcity, $bstate, $bzipcode, $bcountry, $bphone, $bemail, $CardType, hideCardNumber($AccountNumber), $ExpirationMonth, $ExpirationYear);
671
+ pmpro_replaceUserMeta($user_id, $meta_keys, $meta_values);
672
+
673
+ //save first and last name fields
674
+ if (!empty($bfirstname)) {
675
+ $old_firstname = get_user_meta($user_id, "first_name", true);
676
+ if (empty($old_firstname))
677
+ update_user_meta($user_id, "first_name", $bfirstname);
678
+ }
679
+ if (!empty($blastname)) {
680
+ $old_lastname = get_user_meta($user_id, "last_name", true);
681
+ if (empty($old_lastname))
682
+ update_user_meta($user_id, "last_name", $blastname);
683
+ }
684
+
685
+ //show the confirmation
686
+ $ordersaved = true;
687
+
688
+ //hook
689
+ do_action("pmpro_after_checkout", $user_id, $morder); //added $morder param in v2.0
690
+
691
+ //setup some values for the emails
692
+ if (!empty($morder))
693
+ $invoice = new MemberOrder($morder->id);
694
+ else
695
+ $invoice = NULL;
696
+ $current_user->membership_level = $pmpro_level; //make sure they have the right level info
697
+
698
+ //send email to member
699
+ $pmproemail = new PMProEmail();
700
+ $pmproemail->sendCheckoutEmail($current_user, $invoice);
701
+
702
+ //send email to admin
703
+ $pmproemail = new PMProEmail();
704
+ $pmproemail->sendCheckoutAdminEmail($current_user, $invoice);
705
+
706
+ //redirect to confirmation
707
+ $rurl = pmpro_url("confirmation", "?level=" . $pmpro_level->id);
708
+ $rurl = apply_filters("pmpro_confirmation_url", $rurl, $user_id, $pmpro_level);
709
+ wp_redirect($rurl);
710
+ exit;
711
+ } else {
712
+ //uh oh. we charged them then the membership creation failed
713
+ if (isset($morder) && $morder->cancel()) {
714
+ $pmpro_msg = __("IMPORTANT: Something went wrong during membership creation. Your credit card authorized, but we cancelled the order immediately. You should not try to submit this form again. Please contact the site owner to fix this issue.", "pmpro");
715
+ $morder = NULL;
716
+ } else {
717
+ $pmpro_msg = __("IMPORTANT: Something went wrong during membership creation. Your credit card was charged, but we couldn't assign your membership. You should not submit this form again. Please contact the site owner to fix this issue.", "pmpro");
718
+ }
719
+ }
720
+ }
721
+ }
722
+
723
+ //default values
724
+ if (empty($submit)) {
725
+ //show message if the payment gateway is not setup yet
726
+ if ($pmpro_requirebilling && !pmpro_getOption("gateway", true)) {
727
+ if (pmpro_isAdmin())
728
+ $pmpro_msg = sprintf(__('You must <a href="%s">set up a Payment Gateway</a> before any payments will be processed.', 'pmpro'), get_admin_url(NULL, '/admin.php?page=pmpro-membershiplevels&view=payment'));
729
+ else
730
+ $pmpro_msg = __("A Payment Gateway must be set up before any payments will be processed.", "pmpro");
731
+ $pmpro_msgt = "";
732
+ }
733
+
734
+ //default values from DB
735
+ if (!empty($current_user->ID)) {
736
+ $bfirstname = get_user_meta($current_user->ID, "pmpro_bfirstname", true);
737
+ $blastname = get_user_meta($current_user->ID, "pmpro_blastname", true);
738
+ $baddress1 = get_user_meta($current_user->ID, "pmpro_baddress1", true);
739
+ $baddress2 = get_user_meta($current_user->ID, "pmpro_baddress2", true);
740
+ $bcity = get_user_meta($current_user->ID, "pmpro_bcity", true);
741
+ $bstate = get_user_meta($current_user->ID, "pmpro_bstate", true);
742
+ $bzipcode = get_user_meta($current_user->ID, "pmpro_bzipcode", true);
743
+ $bcountry = get_user_meta($current_user->ID, "pmpro_bcountry", true);
744
+ $bphone = get_user_meta($current_user->ID, "pmpro_bphone", true);
745
+ $bemail = get_user_meta($current_user->ID, "pmpro_bemail", true);
746
+ $bconfirmemail = $bemail; //as of 1.7.5, just setting to bemail
747
+ $CardType = get_user_meta($current_user->ID, "pmpro_CardType", true);
748
+ //$AccountNumber = hideCardNumber(get_user_meta($current_user->ID, "pmpro_AccountNumber", true), false);
749
+ $ExpirationMonth = get_user_meta($current_user->ID, "pmpro_ExpirationMonth", true);
750
+ $ExpirationYear = get_user_meta($current_user->ID, "pmpro_ExpirationYear", true);
751
+ }
752
+ }
753
+
754
+ //clear out XXXX numbers (e.g. with Stripe)
755
+ if (!empty($AccountNumber) && strpos($AccountNumber, "XXXX") === 0)
756
+ $AccountNumber = "";
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: strangerstudios
3
  Tags: memberships, membership, authorize.net, ecommerce, paypal, stripe, braintree, restrict access, restrict content, directory site, payflow
4
  Requires at least: 3.5
5
- Tested up to: 4.3
6
- Stable tag: 1.8.5.6
7
 
8
  A revenue-generating machine for membership sites. Unlimited levels with recurring payment, protected content and member management.
9
 
@@ -115,14 +115,44 @@ Not sure? You can find out by doing a bit a research.
115
  [View All Screenshots](http://www.paidmembershipspro.com/features/screenshots/)
116
 
117
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  = 1.8.5.6 =
 
 
119
  * BUG: Fixed $pmpro_core_pages bug added in 1.8.5.5.
120
  * BUG: Removed styling of .input from frontend.css. (Thanks, Russell Jamieson)
 
 
121
 
122
  = 1.8.5.5 =
123
  * BUG: Added a $pmpro_core_pages global and using that in includes/init.php so we don't try to load preheaders and templates for pages added to that from other addons/etc.
124
 
125
  = 1.8.5.4 =
 
 
 
126
  * BUG: Fixed infinite redirect issues that would come up on servers setting $_SERVER['HTTPS'] to 'Off' vs 'off' or false. (Thanks, Gordon Seirup)
127
  * BUG: Using current_time('timestamp') in the sales report to avoid issues where sales at the beginning or end of the day aren't showing up under Today.
128
  * BUG: Fixed issues where delete links using the askfirst() JavaScript function would break for some language settings.
@@ -825,340 +855,4 @@ useful for determining if/what discount code was applied to the level when proce
825
  * Added hooks for changing the discount code page: pmpro_save_discount_code_level, pmpro_save_discount_code, pmpro_discount_code_after_settings, pmpro_discount_code_after_level_settings. Look them up in discountcodes.php to see how they work.
826
  * Updated pmpro_send_html(), which filters emails, to use wpautop instead of nl2br. This will fix any extra double spacing you may have noticed in your emails.
827
  * Added a stripslashes around the membership level confirmation text on the confirmation page. Extra slashes were breaking links, etc.
828
- * Added membership level to subject of checkout confirmation email sent to admins.
829
-
830
- = 1.4.2 =
831
- * Fixed bug that was added slashes into a level's description and confirmation when saving.
832
- * Removed wp_editor use is the blog is running a version of WordPress < 3.3. (Note: We will only officially support the latest version of WordPress with each release.)
833
- * Added the pmpro_pages_shortcode_{membership page} filter. This can be used to filter the content output by the pmpro_checkout and other page shortcodes. e.g. use pmpro_pages_shortcode_checkout to tweak the HTML output of the pmpro_checkout shortcode. The pages are "account", "billing", "cancel", "checkout", "confirmation", and "levels".
834
- * Added a "use_ssl" option. For the PayPal Website Payments Pro and Authorize.net gateways, this must be on. For Stripe, this will default to on, but can be switched off. For PayPal Express and the test gateway, it will default to off but can be switched on. When on, the checkout and update billing pages will be forced to be served over SSL. If off, those pages will redirect to non-ssl versions. The previous hooks/filters for overriding this will still work.
835
- * Added pmpro_save_membership_level and pmpro_membership_level_after_other_settings hooks to be able to add fields to the new/edit membership level page.
836
- * Fixed some more warnings and notices.
837
- * Updated checkout page to use pmpro_isLevelFree() in logic to display recaptcha or not.
838
-
839
- = 1.4.1 =
840
- * Fixed critical bugs with PayPal Express.
841
- * When a PayPal cancellation returns error "11556" (The subscription must have status "active" or "suspended".) I am cancelling the membership without an error. Most likely the PayPal subscription was already cancelled on the PayPal side.
842
- * No longer trying to cancel a subscription with the gateway if a membership/order doesn't have a subscription_transaction_id. (It was a initial payment only membership probably.)
843
-
844
- = 1.4 =
845
- * Rewrote how gateways are handled to make it easier to add and manage new gateway options.
846
- * Added Stripe as a gateway option. (http://www.stripe.com)
847
- * Added a "confirmation message" field to the level editor that is shown on the confirmation page after checking out. The message is added to the text that can be filtered using the pmpro_confirmation_message hook.
848
- * Now applying "the_content" filters on the confirmation message on the confirmation page. e.g. wpautop will be run on the text to automatically add paragraphs.
849
- * Now showing the level description on the checkout page. You can use this code to remove the description from the checkout page: https://gist.github.com/2323424
850
- * The description and confirmation fields of the membership level editor now use WP Editor fields with full WYSIWYG support.
851
- * Fixed the logic around setting the $pmpro_display_ads global, used by the pmpro_displayAds() and pmpro_hideAds() functions.
852
- * Fixed bug with recaptcha logic.
853
- * Updated /pages/checkout.php to use wp_login_url function for login link.
854
- * Small changes to pmpro_changeMembershipLevel function to support deleting users when they cancel their account.
855
- * Added the pmpro_member_links_top and pmpro_member_links_bottom hooks so you can add links to the "Member Links" list of the account page. Just output an a tag wrapped in a li tag. (May tweak this to build an array of links that can be filters, but this is good for now.)
856
- * Fixed some more notices.
857
-
858
- = 1.3.19 =
859
- * Rewrote the pmpro_login_redirect function. It's cleaner now. Important: there was a pmpro_login_redirect hook in there that was fairly redundant with the core login_redirect hook. I've renamed the pmpro hook to pmpro_login_redirect_to because I had a hook with the same name (pmpro_login_redirect) used in a different place to control whether or not PMPro redirects the register page to the levels page. Having one hook for two things is a bad idea. It seems like more people were using the hook for controlling the registration redirect, so I left that one alone and renamed these.
860
- * Changed PMPro page creation to set all membership pages as subpages of the membership account page. This results in nicer menus for themes that add all top level pages to the menu.
861
- * Updated the checkout page to submit to "" (itself) instead of echoing the checkout page URL here. (Since we can have multiple checkout pages.) This also fixes from SSL conflicts that may crop up on the checkout page.
862
- * Updated the priority of a few actions/hooks so the "besecure" https stuff gets run as soon as possible. Before it was possible that some URLs could be written out with http: on an HTTPS page before PMPro had a chance to fix things. You should have fewer SSL errors on the checkout page to deal with now.
863
- * Added an option on the payment settings page to "nuke" http: links on all secure pages. This option can add time to your page loads, but will ensure that all http: links for your domain are replaced with https: links.
864
- * Allowing multiple pages to use the [pmpro_checkout] shortcode so you can create multiple checkout pages. This is good if you want a separate templated checkout page for each membership level or product you have.
865
- * You can now add a pmpro_default_level custom field, set to the id # of the level you want, that will be used if you navigate directly to a checkout page without setting a level.
866
- * Added some stuff to support adding shipping fields via hooks. Add this plugin to your site, edit, and activate to add shipping to your checkout: https://gist.github.com/1894897
867
- * Removed the price from the description sent to PayPal. The DESC field is limited to 127 characters and must match up across API calls. So there is a good chance the price would get truncated which could be confusing. This was a kind of hack anyway. PayPal should show the price data it has. Not sure why it won't. The price is still reviewed on the review page of your site though.
868
- * The recaptcha code now checks for a previous error before changing pmpro_msg to "All Good".
869
- * Fixed warning in pmpro_has_membership_access(). Fixed a bunch of other warnings here and there.
870
- * Rewrote pmpro_updateMembershipCategories() just to be cleaner
871
- * Added pmpro_state_dropdowns filter. If you return true, the state field will become a dropdown with US states. Use the pmpro_states and pmpro_states_abbreviations filters to change the array of states used.
872
-
873
- = 1.3.18.1 =
874
- * Added the new email .html templates to svn.
875
-
876
- = 1.3.18 =
877
- * Fixed some warnings: admin bar warning that showed up on admin pages; warning issued by pmpro_setOption(); warning in pmpro_hasMembershipLevel(); warning in billing update; warnings on the user edit page; warnings in the getTax method of the order class; warnings in save method of order class.
878
- * Added a pmpro_checkout_confirm_email filter that can return false to hide and not require the "Confirm E-mail" field at checkout.
879
- * Added a pmpro_checkout_confirm_password filter that can return false to hide and not require the "Confirm Password" field at checkout.
880
- * If the PMPRO_DEFAULT_LEVEL constant is set, traffic on the levels page is redirected to the checkout page. This redirect no longer forces HTTPS.
881
- * Moved the pmpro_paypalexpress_session_vars hook call so it will run even if existing users are checking out (upgrades, etc).
882
- * Added some confirmation emails for admins: (1) for new user signups, (2) when an admin changes a member's level, (3) when a user cancel's their membership, and (4) when a user update's their billing information. New email templates (ending with "_admin.html") have been added to the /email/ folder of the plugin.
883
- * Added new email settings to enable/disable the new admin emails. They will be enabled by default on install and upgrade to 1.3.18. The settings are on the email tab of the PMPro settings.
884
- * Added a couple hooks to the checkout page to have more control over where you add fields, etc. pmpro_checkout_before_submit_button and pmpro_checkout_after_billing_fields.
885
-
886
- = 1.3.17.1 =
887
- * Fixing activation bug from 1.3.17.
888
-
889
- = 1.3.17 =
890
- * Updated pmpro_hasMembershipLevel() and [membership] shortcode to allow passing a level like "-5" which will return true if the user does NOT have level #5.
891
- * Updated how PMPro notifications are retrieved and shown on the PMPro admin pages. We're using admin-ajax to call the pmpro_notifications function which uses WP's HTTP API to call the www.paidmembershipspro.com server. Only the PMPro version number is passed to check if a notification should be shown. This method shouldn't slow page load since the javascript is called using jQuery's ready function. If the PMPro server is unavailable, you'll get a JS error instead of a PHP one.
892
- * Fixed warning on discount codes page. Fixed some other warnings.
893
- * Updated expiration/trial crons to avoid blank ('') and zero ('0000-00-00 00:00:00') DB values in addition to NULLs. (Some backup programs will incorrectly export NULL dates as '' which could be interpretted as 1/1/1970... meaning the membership has expired.)
894
- * Fixed bug where "Billing Information" was shown on the account page for some free levels.
895
-
896
- = 1.3.16 =
897
- * Moved the SSL Seal box lower on the payment settings page.
898
- * Made dashboard menu and admin bar menus consistent.
899
- * Fixed bug with selecting categories when adding a new level.
900
- * Fixed bug where the user was sometimes redirected to the add level page after adding a level.
901
-
902
- = 1.3.15 =
903
- * Fixed SSL handling on the billing page for members without an order.
904
- * Removed single quotes from shortcode examples on page settings page. Doh! (Thanks, Caps)
905
- * Added Multisite/Network FAQ item.
906
- * Updated the payments settings page to convert tax rates like 7 into 0.07. (Tax rates > 1 are divided by 100.)
907
-
908
- = 1.3.14 =
909
- * Added pmpro_show_cvv filter to hide the CVV from the checkout and billing information pages.
910
- * Updated the billing page to use the pmpro_required_billing_fields like the checkout page does.
911
- * Updated the Authorize.net integration to not pass an empty CVV if the value is empty. Authorize.net will still throw an error if you require CVV via your gateway settings. If you update your settings and PMpro to not require a CVV, you won't get an error.
912
- * Passing the level cost to PayPal Express through the description.
913
- * The billing page doesn't require SSL now if the gateway for the order was PayPal Express. A link to PayPal is shown instead of the form. (Be sure to remove the "becesure" custom field from your billing page if it has one and you don't want this page served over SSL.)
914
- * Fixed bug where the membership level name wasn't being passed to Authorize.net in the description field for the order.
915
- * Added a second paramter ($tags = true) to the pmpro_getLevelCost function. If this is false, strip_tags is run on the cost before returning it. (By default we wrap the prices in <strong> tags which is not good for passing to PayPal for example.)
916
- * Some bug fixes for updating billing against Authorize.net.
917
-
918
- = 1.3.13 =
919
- * Fixed warning on checkout page. (Thanks Caps!)
920
- * Fixed bug in PayPal Express checkout that resulted in trying to load the confirmation page over SSL (which would break on some servers). (Thanks Caps!)
921
- * Updated getTaxFromPrice method of order class to allow for better filtering, by level, etc. The pmpro_tax filter now passes the $tax amount, $values (array with price passed and other values), and $this (the order object). It's a little clunky, but must be for backwards compatibility. Custom tax example here: http://www.paidmembershipspro.com/2012/02/custom-tax-structure-using-the-pmpro_tax-hook/
922
- * Removed all TAXAMT NVP parameters in PayPal Express calls. Including these would sometimes introduce errors during checkout. The tax amount is still included in the total amounts passed. Not sure what impact dropping the TAXAMT property will have on reporting in PayPal. I don't believe their tax reporting is the best anyway. Maybe we can build a tax report into PMPro.
923
-
924
- = 1.3.12 =
925
- * Fixed bug in members list pagination on sites installed in a subdirectory.
926
- * Now swapping out the PayPal Express checkout button if the level is free or becomes free with a discount code. (Thanks, Caps!)
927
-
928
- = 1.3.11 =
929
- * Fixed bug with cancelling a user's membership through the admin.
930
-
931
- = 1.3.10 =
932
- * Fixed the links in the discount code table.
933
- * pmpro_hasMembershipLevel(0) and [membership level="0"] will once again return true for non-members. (This broke whent he pmpro_has_membership_level filter was added.)
934
- * WP 3.3.1 testing. (Looks good!)
935
-
936
- = 1.3.9 =
937
- * Added a "pmpro_has_membership_level" filter ($r = apply_filters("pmpro_has_membership_level", $r, $user_id, $levels);) which can be used to override the default behavior here.
938
- * Fixed the pmpro shortcodes to allow content above and below the shortcodes on the membership pages. (Thanks, Bluewind!)
939
- * Now setting the user's first and last name to the billing first and last name after checkout.
940
- * Added billing first/last name, billing address, and phone number to the members list screen and CSV export.
941
- * Removed email header/footer code from email class because sometimes it was added twice. Now it is added by the pmpro_send_html function in paid-memberships-pro.php for all emails (WP or PMPro) if a header or footer file are found in your theme folder.
942
- * Added a pmpro_after_phpmailer_init. (The old hook pmpro_after_pmpmailer_init had a typo -- pmpmailer instead of phpmailer.) I left the old hook in for backwards compatibility.
943
-
944
- = 1.3.8 =
945
- * Fixed a bug with canceling memberships. Important Note: User requested cancellations were not being forwarded to PayPal and Authorize.net in the past couple updates. Please double check your members lists with your payment gateway subscriptions. Sorry for the inconvenience.
946
- * Fixed a bug in the billing update form.
947
- * Wrapped some output on the billing update form in esc_attr.
948
- * Now sorting countries alphabetically if international orders are turned on.
949
- * Updated the membership-billing page to show country and long form fields if enabled via the hooks pmpro_international_addresses and pmpro_longform_address. (These were only showing up on the checkout form before.)
950
-
951
- = 1.3.7 =
952
- * Added "expiration" field to user profile page. Updated the email class to include information on expiration dates in the admin change emails.
953
- * Added "pmpro_profile_show_membership_level" and "pmpro_profile_show_expiration" filters which will hide those fields from the edit profile screen if false is returned.
954
- * Added a pmpro_getMembershipLevelForUser($user_id) function and replaced some redundant code in a few places where we query the DB for this. Maybe we'll have a membership level class as some point. Makes sense now.
955
- * Fixed bug where the wrong price for levels was showing up on the edit profile page in the admin. (It would show the current user's level info instead of the edited user's info.)
956
- * Cleaned up a few more warnings, etc.
957
-
958
- = 1.3.6 =
959
- * Changed a few split() calls to explode() to avoid warnings.
960
- * Fixed a couple other warnings/notifices.
961
- * Updated account page to hide the change billing info link if the user doesn't have an active subscription or signed up with PayPal Express.
962
- * Added a filter pmpro_paypal_express_return_url_parameters which can be used to add parameters to the ReturnURL when checking out with PayPal Express. Return an array of key, value pairs. { return array("option" => "1"); }
963
-
964
- = 1.3.5 =
965
- * Important update to Authorize.net processing code to account for the "credit card expires before the start of this subscription" error that comes up. For levels/discount codes with no trials or only free trials/initial payments, the subscription setup with Authorize.net starts the day of checkout and a free trial is tacked on for 1 period vs. setting up the subscription one period out. One period is added to the billing limit as well, if applicable. Check the blog for more information.
966
- * Important update for PayPal Website Payments Pro users. When using PayPal WPP, the user will have an option to checkout via PayPal Express as well. PayPal requires this and now we support it.
967
-
968
- = 1.3.4 =
969
- * Swapped the $ in the levels page code for $pmpro_currency_symbol.
970
- * Changed the membership shortcode to apply the_content filters to the return value instead of just wpautop. This allows shortcodes within that shortcode and other filters to be run on the content. (Let me know if issues arrise from this.)
971
- * Wrapped some post variables in checkout and billing preheaders with trim()
972
- * Now voiding authorizations with Authorize.net. (The plugin will authorize $1 before setting up a subscription without an initial payment.)
973
- * Now voiding an initial payment with Authorize.net if the subscription setup fails.
974
- * Now refunding an intial payment with PayPal if the subscription setup fails.
975
- * Added a "pmpro_checkout_after_level_cost" to add fields or arbitrary code after the level cost description on the checkout page.
976
- * Added Diner's Club, EnRoute, and JCB as credit card options. Make sure you congiture your Gateway/Merchant account to accept these card types as well.
977
-
978
- = 1.3.3 =
979
- * Fixed bug where country field was resetting to default when there were errors with the checkout form submission. (If you templatized your checkout page and have international addresses enabled, you will need to add $bcountry to the globals setup at the top of your checkout template .php)
980
-
981
- = 1.3.2 =
982
- * Fixed issue introduced in 1.3.1 where checkout page would not redirect to HTTPS when it should have.
983
- * Fixing issues with slashes in addresses/etc in the checkout form.
984
- * Updated the PMProEmail class to use the wp_mail function instead of use PHPMailer directly. (Thanks VadaPrime: http://wordpress.org/support/topic/plugin-paid-memberships-pro-wp_mail?replies=6#post-2449672)
985
- * Fixed some more notices and warnings.
986
-
987
- = 1.3.1 =
988
- * Fixed automatic page creation, which broke in the last update.
989
- * Added hook pmpro_checkout_level which allows you to tweak the $level object before checkout, e.g. to change pricing for upgrades.
990
- * Added hook pmpro_checkout_start_date which allows you to change the start date of a membership before checkout. (preheaders/checkout.php)
991
- * Added hook pmpro_profile_start_date which allows you to change the start date of a membership that is sent to the gateway. (classes/class.memberorder.php)
992
- * Cleaned up some notices and warnings. Will hopefully finish the remaining ones next update.
993
- * Removed some old tinyMCE code that wasn't in use anymore. FYI, WP 3.3 will have a way to include visual editors on other pages, so we may add it to the description field of the membership levels.
994
- * Updated order class to send phone and email to Authorize.net when creating subscriptions. The charge/authorize API support international phone numbers, but the ARB API does not. So if a customer enters an international phone number (or other phone number over 10 characters), the number will be sent for any initial payment/charge, but not for the subscription setup.
995
- * Fixed where !!discount_code!! was not being parsed out in emails.
996
-
997
- = 1.3 =
998
- * Added a filter pmpro_login_redirect. You can return false to allow users to signup via the default WP login page.
999
- * Member CSV export no longer limiting to 15 members.
1000
- * Correctly adding code_id to the pmpro_memberships_users table on signup. View here for retroactively updating your users tables in case you intend to use that value for advanced functionality.
1001
- * Changed URL to send IPN checks for live PayPal instances from www.live.paypal.com to www.paypal.com.
1002
- * Updated getfile.php to work when WP is installed in a subdomain.
1003
- * Added links to individual settings tabs in the WP menu.
1004
- * Changed the architecture of the settings pages which used to all be coded in the membershiplevels.php page. Each settings page has its own script now. I removed the pmpro-data.php service and have the pages submit to themselves now. This won't impact how things work, but will make it easier for me to develop going forward.
1005
-
1006
- = 1.2.10 =
1007
- * Added pmpro_confirmation_message hook to change the output on the confirmation page without having to templatize it. The filter passes the constructed html string with the confirmation message and a second parameter containing the order/invoice object if it is a paid membership.
1008
- * Added a pmpro_checkout_boxes hook that can be used to output extra fields and other content in the middle of the checkout page.
1009
- * Now showing 2 decimals places for the tax rate when showing a membership level's cost.
1010
-
1011
- = 1.2.9 =
1012
- * IMPORTANT fix so new user email addresses are properly captured when using PayPal Express.
1013
- * rewrote the IPN handler to use the WordPress HTTP API for better compatibility.
1014
- * added extra id to tables and fields for easier styling. (let me know if you have suggestions for small changes like these that can save you from having to templatize a page)
1015
- * fixed query in readiness check function.
1016
- * Authorize.net doesn't support international phone numbers, so we're not sending them to Authorize.net anymore.
1017
-
1018
- = 1.2.8 =
1019
- * Ordering levels by id (ascending) on the levels page now. Added a "pmpro_levels_array" filter that can be used to reorder the levels or alter the levels before displaying them on the levels page. The array of levels is the only parameter.
1020
- * Added expiration date to the member list and export.
1021
- * Showing a member count on the member list page.
1022
- * Added filter to change subject lines for PMPro emails. (pmpro_email_subject) The filter's first paramter is the subject, the second parameter is an object containg all of the email information. There are also filters for pmpro_email_recipient, pmpro_email_sender, pmpro_email_sender_name, pmpro_email_template, amd pmpro_email_body.
1023
- * Added an RSS feed from the PMPro blog to the dashboard.
1024
- * Now only showing the discount code field at checkout if there are discount codes in the database. Can be overriden by the pmpro_show_discount_code filter.
1025
- * Cancelling with PayPal now properly updates status to "cancelled".
1026
- * No longer trying to unsubscribe from PayPal or Authorize.net if there is no subscription ID to check against (e.g. when the user was manually added to a membership level) or if the last order does not have "success" status (e.g. they already cancelled).
1027
- * Removed PHP short tags (e.g., <?=$variable?>) for wider compatibility.
1028
-
1029
- = 1.2.7 =
1030
- * Fixed bug with non-USD currencies.
1031
- * Fixed bug with phone number formatting.
1032
-
1033
- = 1.2.6 =
1034
- * Fixed bug with discount codes showing up in emails, confirmation pages, and invoices.
1035
- * Added currency option to gateway settings.
1036
-
1037
- = 1.2.5 =
1038
- * PayPal Express support! PayPal Express requires just a verified PayPal Business account (no monthly fees from PayPal).
1039
- * Fixed a bug when plans with a "cycle number"/billing frequency that was greater than 1 (e.g. every 4 months). Before the first payment was being scheduled 1 day/month ext out instead of e.g. 4 months out... resulting in an extra payment.
1040
- * Added some hooks to support international orders: pmpro_international_addresses, pmpro_default_country, pmpro_countries, pmpro_required_billing_fields. Example code to support international credit cards: https://gist.github.com/1212479
1041
-
1042
- = 1.2.4 =
1043
- * VERY IMPORTANT BUG FIX: The getMembershipLevel function of the MemberOrder class had an error where the membership level object was not being created properly during signup and so * recurring subscriptions were not being created *. This update fixes the bug. Thanks to mvp29 for catching this.
1044
- * Fixed another bug that was causing warnings on some setups, e.g. WAMP server for Windows.
1045
- * Fixed a bug that would show warnings when visiting a login page over HTTPS.
1046
- * Fixed membership pricing wording for certain cases, e.g. every 4 months for 4 more payments.
1047
- * Fixed a bug in the email generation for order confirmations when discount codes were used. This will no longer freeze the screen.
1048
-
1049
- = 1.2.3 =
1050
- * Fixed an error in the DB upgrade code that was keeping the "enddate" from being added to new members' records.
1051
-
1052
- = 1.2.2 =
1053
- * Added pmpro_skip_account_fields hook. This value is used to determine if the username/password accounts fields should show up at checkout. By default, it is shown when the user is logged out and not shown when logged in. The hook allows you to return true or false to override this behavior. If the fields are skipped while no user is logged in a username and password will be automatically generated for the new user after checkout.
1054
- * You can delete discount codes now from the admin.
1055
- * Added a hook pmpro_level_cost_text to allow you to override how the cost is shown on the checkout page. Obviously don't abuse this by showing a different price than what will be charged. Be careful if you change your membership levels pricing to update your filter if needed. The hook passes the text generated by the pmpro_getLevelCost(&$level) function and also a level object which is prepopulated with levels pricing and expiration settings already adjusted for any discount codes that may be in affect.
1056
- * Added expiration settings for levels. You can set an "expiration number" and "expiration period" for any level now. e.g. "6 months" or "180 days". You can also alter expiration settings via discount codes. Expirations will be useful for offering free trials which don't require a credit card... and other scenarios you guys have come up with. A script is run once a day using WP Cron that checks for any membership that has ended and then cancels that membership. The user will lose access and the subscription setup in your payment gateway will be canceled.
1057
- * Users can "extend" a membership that is set to expire via the Membership Account page.
1058
- * Added a hook pmpro_level_expiration_text to allow you to override how the expiration information is shown on the levels and checkout pages. Again don't abuse this by showing a different expiration than is real. Be careful if you change your expiration settings to update your filter if needed. The hook passes the text generated by the pmpro_getLevelExpiration(&$level) function and also a level object which is prepopulated with levels pricing and expiration settings already adjusted for any discount codes that may be in affect.
1059
- * Added an error check if the MySQL insertion of the membership level fails. This happens after the user's credit card/etc has already been charged. The plugin tries to cancel the order just made, but might fail. The user is adviced to contact the site owner instead of trying again. I don't want to scare you. We test the checkout process a lot. So assuming that the code hasn't been tampered with and there isn't an internet outage in the microseconds between the order going through and the database being updates, you should never run into this. Still it's nice to have, just in case.
1060
- * Fixed a bug that may have caused the billing amount to show up incorrectly on the Membership Account page.
1061
- * Added the discount code used to the confirmation page, invoices, and invoice emails.
1062
- * Now sending notification emails to members 1 week before their trial period ends (if applicable). A WP cron job is setup on plugin activation. You can disable the email via the pmpro_send_trial_ending_email hook.
1063
- * Now sending notification emails to members 1 week before their membership expires (if applicable). A WP cron job is setup on plugin activation. You can disable the email via the pmpro_send_expiration_warning_email hook.
1064
- * An email is sent when a membership expires. A WP cron job is setup on plugin activation. You can disable the email via the pmpro_send_expiration_email hook.
1065
- * Note: Right now users cannot "extend" a membership that is about to expire without first canceling their current membership. I plan to add "membership extensions" for these cases, but it's a little complicated and I didn't want to hold up this release for them. So Real Soon Now.
1066
-
1067
- = 1.2.1 =
1068
- * Fixed bug where non-member admins would be redirected away from the "All Pages" page in the admin.
1069
-
1070
- = 1.2 =
1071
- * Fixing some wonkiness with the 1.1.15 update.
1072
- * Fixed "warning" showing up on discount code pages.
1073
- * Tweaked the admin pages a bit for consistency.
1074
- * Added screenshots and FAQ to the readme.
1075
- * Figured we were due for a bigger version step.
1076
-
1077
- = 1.1.15 =
1078
- * Discount Codes Added!
1079
- * Removed some redundant files that slipped into the services folder.
1080
- * Fixed the !!levels!! variable for message settings of the advanced tab.
1081
- * Changing some ids columns in tables to unsigned.
1082
-
1083
- = 1.1.14 =
1084
- * Now encoding #'s when sending info via Authorize.net's API. This may prevent some address conflicts.
1085
-
1086
- = 1.1.13 =
1087
- * No longer adding "besecure" custom field to the billing and checkout pages. You can still add this manually to selectively require SSL on a page. If you are trying to do a free membership without SSL, you will have to make sure the besecure custom field is deleted from the Membership-Checkout page, especially if you are upgrading from an older version of PMPro.
1088
- * Added a filter before sending the default WP welcome notification email. Return false for the "pmpro_wp_new_user_notification" hook/filter to skip sending the WP default welcome email (because in many cases they are already getting an email from PMPro as well).
1089
-
1090
- = 1.1.12 =
1091
- * Revenue report on members list page. (Rought estimate only that doesn't take into account trial periods and billing limits.)
1092
- * Enabling weekly recurring payments for Authorize.net by converting week period to 7 days * # months.
1093
- * Improved error handling on checkout page.
1094
- * Now running "pmpro_after_change_membership_level" actions after the "pmpro_after_checkout" action. Previously this hook was only called when a membership level was changed via the WP admin.
1095
- * Won't complain about setting up a Payment Gateway if you only have free membership levels.
1096
- * The "besecure" custom field is not added to the billing or checkout by default anymore when you run the "create the pages for me" option in the settings. Whether or not to use HTTPS on a page is now handled in the preheader files for each page (see below).
1097
- * The plugin won't force SSL on the checkout page anymore unless the membership level requires payment. If your checkout page is still running over HTTPS/SSL for free membership checkouts, make sure the "besecure" custom field has been deleted on your checkout page. You can use the "besecure" custom field or the "pmpro_besecure" filter to override the plugin's decision.
1098
- * The plugin won't force SSL on the cancel page anymore. Again, you can override this using the "besecure" custom field or the "pmpro_besecure" filter.
1099
-
1100
- = 1.1.11 =
1101
- * Removed some debug code from the invoice page that might have shown on error.
1102
- * Added check to recaptcha library code incase it is already installed. (Let's hope other plugin developers are doing the same.)
1103
- * Removed the TinyMCE editor from the description field on the edit membership level page. It was a little buggy. Might bring it back later.
1104
-
1105
- = 1.1.10 =
1106
- * added a hook/filter "pmpro_rss_text_filter"
1107
- * added a hook/filter "pmpro_non_member_text_filter"
1108
- * added a hook/filter "pmpro_not_logged_in_text_filter"
1109
- * adjusted the pmpro_has_membership_access() function
1110
- * added a hook/filter "pmpro_has_membership_access_filter"
1111
- * updated the hook/filter "pmpro_has_membership_access_filter_{post-type}"
1112
- * removed the "pmpro_has_membership_access_action_{post-type}" hook/action
1113
- * update invoice page to handle case where no invoice is found
1114
-
1115
- = 1.1.9 =
1116
- * You can now set individual posts to require membership without assigning them to a category.
1117
- * Fixed bug with the confirmation email during signup.
1118
- * Fixed a CSS bug on the cancel membership page.
1119
-
1120
- = 1.1.8 =
1121
- * Fix for login/registration URL rerouting.
1122
- * Added members list to admin bar menu.
1123
- * Added warning/error when trying to checkout before the payment gateway is setup.
1124
- * Fixed some error handling in the order class.
1125
- * Fixed a bug that occurred when processing amounts less than $1.
1126
-
1127
- = 1.1.7 =
1128
- * Fixed bugs with http to https redirects and visa versa.
1129
- * Fixed redirect bugs for sites installed in a subdomain.
1130
-
1131
- = 1.1.6 =
1132
- * Fixed MySQL bug showing up on some users add membership level page.
1133
-
1134
- = 1.1.5 =
1135
- * Required fix for PayPal Website Payments Pro processing. Please update.
1136
- * Fixed bug with pagination on members list.
1137
- * Fixed bugs with errors thrown by MemberOrder class.
1138
- * Updated login/registration URL rerouting.
1139
-
1140
- = 1.1.4 =
1141
- * Custom Post Types default to allowing access
1142
- * Fixed login_redirect code.
1143
- * Added pmpro_login_redirect filter for when members login.
1144
-
1145
- = 1.1.3 =
1146
- * Getting ready for the WP plugin repository
1147
- * License text update.
1148
-
1149
- = 1.1.2 =
1150
- * Added hooks to checkout page for customizing registration fields.
1151
- * Fixed bug in pmpro_getLevelCost();
1152
- * Another CCV/CVV fix for Authorize.net.
1153
- * License text update.
1154
- * Admin notices are loaded via Ajax now.
1155
-
1156
- = 1.1.1 =
1157
- * Added honeypot to signup page.
1158
- * Updated pmpro_add_pages to use capabilities instead of user levels
1159
- * Fixed checkboxes in admin screens.
1160
- * Now checking that passwords match on signup.
1161
- * Properly sending CCV/CVV codes to Authorize.net.
1162
-
1163
- = 1.0 =
1164
- * This is the launch version. No changes yet.
2
  Contributors: strangerstudios
3
  Tags: memberships, membership, authorize.net, ecommerce, paypal, stripe, braintree, restrict access, restrict content, directory site, payflow
4
  Requires at least: 3.5
5
+ Tested up to: 4.3.1
6
+ Stable tag: 1.8.6.2
7
 
8
  A revenue-generating machine for membership sites. Unlimited levels with recurring payment, protected content and member management.
9
 
115
  [View All Screenshots](http://www.paidmembershipspro.com/features/screenshots/)
116
 
117
  == Changelog ==
118
+ = 1.8.6.2 =
119
+ * BUG: Stripe supports daily recurring subscriptions. Fixed issue where PMPro was still throwing a warning in some cases.
120
+ * BUG: Removed warnings in the membership stats report.
121
+ * CODE: Changed a couple instances of "since v2.0" to "since v1.8".
122
+ * ENHANCEMENT: Added a hook for pmpro_checkout_order_free that functions like pmpro_checkout_order but fires for the blank order created for free checkouts.
123
+ * ENHANCEMENT: Using site_url to get full URL to for the redirect_to value generated by !!referrer!! in the non-member/logged-out text strings in the advanced settings page. This fixes issues with using !!referrer!! on multisite setups. (Thanks, Keith Hall)
124
+ * ENHANCEMENT: Updated pmpro_post_classes to work on the $post_id passed by the filter instead of the global $post variable.
125
+ * ENHANCEMENT: Added pmpro_body_classes to add classes like pmpro-body-level-required, pmpro-body-level-1, and pmpro-body-has-access to the body tag based on the queried object.
126
+ * ENHANCEMENT: Reformatted the PMPro Reports dashboard.
127
+ * ENHANCEMENT: Now using separate invoice templates for email and print.
128
+
129
+ = 1.8.6.1 =
130
+ * SECURITY: Removed debug code from the PayPal IPN Handler script that was causing invalid IPN requests to process as if they were valid. (Thanks, Francois Harvey)
131
+
132
+ = 1.8.6 =
133
+ * BUG: The pmpro_membership_level_profile_fields_update() function now only fires on the personal_options_update and edit_user_profile_update hooks instead of the profile_update hook since this function expects to be called from the your-profile or edit-user page.
134
+ * FEATURE: Added the ability to print invoices/orders from the Memberships -> Orders page in the dashboard. (Thanks, AgResources)
135
+ * FEATURE: Added the ability to email invoices/orders from the Memberships -> Orders page in the dashboard. (Thanks, AgResources)
136
+ * ENHANCEMENT: Added pmpro_before_change_membership_level action. Runs before the subscriptions are cancelled and before the SQL executes to change a user's level. Passes $level_id and $user_id.
137
+ * ENHANCEMENT: Updated Stripe Web Hook handler to save event into global $pmpro_stripe_event so filters can act on it.
138
+ * ENHANCEMENT: Added $pmpro_level as a second parameter for the pmpro_setup_new_user filter. (Thanks, David Crabill)
139
+ * ENHANCEMENT: Added Vietnamese language pack. (Thanks, Alex Training Center)
140
+
141
  = 1.8.5.6 =
142
+ * ENHANCEMENT: Added pmpro_payflow_authorize_nvpstr, pmpro_payflow_void_nvpstr, pmpro_payflow_charge_nvpstr, pmpro_payflow_subscribe_nvpstr, pmpro_payflow_update_nvpstr, pmpro_payflow_cancel_nvpstr filters for PayPal Payflow Pro gateway. Usage is the same as PayPal Express NVP string filters.
143
+ * ENHANCEMENT: Added printable and emailable invoice templates to the Orders page.
144
  * BUG: Fixed $pmpro_core_pages bug added in 1.8.5.5.
145
  * BUG: Removed styling of .input from frontend.css. (Thanks, Russell Jamieson)
146
+ * BUG: Commented out a console.log call from Stripe JavaScript code. (Still there to uncomment if you want to debug.)
147
+ * ENHANCEMENT: No longer requiring the CVC/CVV code with Stripe. If blank, Stripe will try to verify without it. If your Stripe settings are to decline transactions that fail CVC check, you will still need a valid CVC code at checkout.
148
 
149
  = 1.8.5.5 =
150
  * BUG: Added a $pmpro_core_pages global and using that in includes/init.php so we don't try to load preheaders and templates for pages added to that from other addons/etc.
151
 
152
  = 1.8.5.4 =
153
+ * ENHANCEMENT: Added pmpro_get_membership_level_for_user and pmpro_get_membership_levels_for_user filters to change the levels returned for a user with the pmpro_getMembershipLevelForUser() and pmpro_getMembershipLevelsForUser() functions.
154
+ * ENHANCEMENT: Updated pmpro_hasMembershipLevels() function to search for expired members with "e" or "E". Also applies to [membership] shortcodes.
155
+ * ENHANCEMENT: Added the pmpro_extra_page_settings filter to add additional page settings fields for use with add-on plugins, etc.
156
  * BUG: Fixed infinite redirect issues that would come up on servers setting $_SERVER['HTTPS'] to 'Off' vs 'off' or false. (Thanks, Gordon Seirup)
157
  * BUG: Using current_time('timestamp') in the sales report to avoid issues where sales at the beginning or end of the day aren't showing up under Today.
158
  * BUG: Fixed issues where delete links using the askfirst() JavaScript function would break for some language settings.
855
  * Added hooks for changing the discount code page: pmpro_save_discount_code_level, pmpro_save_discount_code, pmpro_discount_code_after_settings, pmpro_discount_code_after_level_settings. Look them up in discountcodes.php to see how they work.
856
  * Updated pmpro_send_html(), which filters emails, to use wpautop instead of nl2br. This will fix any extra double spacing you may have noticed in your emails.
857
  * Added a stripslashes around the membership level confirmation text on the confirmation page. Extra slashes were breaking links, etc.
858
+ * Added membership level to subj
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
services/stripe-webhook.php CHANGED
@@ -41,32 +41,33 @@
41
  {
42
  try
43
  {
44
- $event = Stripe_Event::retrieve($event_id);
 
45
  }
46
  catch(Exception $e)
47
  {
48
  $logstr .= "Could not find an event with ID #" . $event_id . ". " . $e->getMessage();
49
  pmpro_stripeWebhookExit();
50
- //$event = $post_event; //for testing you may want to assume that the passed in event is legit
51
  }
52
  }
53
 
54
  global $wpdb;
55
 
56
  //real event?
57
- if(!empty($event->id))
58
  {
59
  //check what kind of event it is
60
- if($event->type == "charge.succeeded")
61
  {
62
  //do we have this order yet? (check status too)
63
- $order = getOrderFromInvoiceEvent($event);
64
 
65
  //no? create it
66
  if(empty($order->id))
67
  {
68
  //last order for this subscription
69
- $old_order = getOldOrderFromInvoiceEvent($event);
70
 
71
  if(empty($old_order))
72
  {
@@ -84,7 +85,7 @@
84
  pmpro_stripeWebhookExit();
85
  }
86
 
87
- $invoice = $event->data->object;
88
 
89
  //alright. create a new order/invoice
90
  $morder = new MemberOrder();
@@ -133,7 +134,7 @@
133
  $pmproemail = new PMProEmail();
134
  $pmproemail->sendInvoiceEmail($user, $morder);
135
 
136
- $logstr .= "Created new order with ID #" . $morder->id . ". Event ID #" . $event->id . ".";
137
 
138
  /*
139
  Checking if there is an update "after next payment" for this user.
@@ -207,14 +208,14 @@
207
  }
208
  else
209
  {
210
- $logstr .= "We've already processed this order with ID #" . $order->id . ". Event ID #" . $event->id . ".";
211
  pmpro_stripeWebhookExit();
212
  }
213
  }
214
- elseif($event->type == "charge.failed")
215
  {
216
  //last order for this subscription
217
- $old_order = getOldOrderFromInvoiceEvent($event);
218
  $user_id = $old_order->user_id;
219
  $user = get_userdata($user_id);
220
 
@@ -252,16 +253,16 @@
252
  }
253
  else
254
  {
255
- $logstr .= "Could not find the related subscription for event with ID #" . $event->id . ".";
256
- if(!empty($event->data->object->customer))
257
- $logstr .= " Customer ID #" . $event->data->object->customer . ".";
258
  pmpro_stripeWebhookExit();
259
  }
260
  }
261
- elseif($event->type == "customer.subscription.deleted")
262
  {
263
  //for one of our users? if they still have a membership, notify the admin
264
- $user = getUserFromCustomerEvent($event, "success", true);
265
  if(!empty($user->ID))
266
  {
267
  do_action("pmpro_stripe_subscription_deleted", $user->ID);
@@ -270,17 +271,17 @@
270
  $pmproemail->data = array("body"=>"<p>" . sprintf(__("%s has had their payment subscription cancelled by Stripe. Please check that this user's membership is cancelled on your site if it should be.", "pmpro"), $user->display_name . " (" . $user->user_login . ", " . $user->user_email . ")") . "</p>");
271
  $pmproemail->sendEmail(get_bloginfo("admin_email"));
272
 
273
- $logstr .= "Subscription deleted for user ID #" . $user->ID . ". Event ID #" . $event->id . ".";
274
  pmpro_stripeWebhookExit();
275
  }
276
  else
277
  {
278
  //check for any user at all
279
- $user = getUserFromCustomerEvent($event);
280
  if(!empty($user->ID))
281
- $logstr .= "Stripe tells us a subscription is deleted. This was probably initiated from PMPro and the membership/order is already cancelled. Event ID #" . $event->id . ".";
282
  else
283
- $logstr .= "Stripe tells us a subscription is deleted, but we could not find a user here for that subscription. Could be a subscription managed by a different app or plugin. Event ID #" . $event->id . ".";
284
  pmpro_stripeWebhookExit();
285
  }
286
  }
@@ -294,14 +295,14 @@
294
  pmpro_stripeWebhookExit();
295
  }
296
 
297
- function getUserFromInvoiceEvent($event)
298
  {
299
  //pause here to give PMPro a chance to finish checkout
300
  sleep(PMPRO_STRIPE_WEBHOOK_DELAY);
301
 
302
  global $wpdb;
303
 
304
- $customer_id = $event->data->object->customer;
305
 
306
  //look up the order
307
  $user_id = $wpdb->get_var("SELECT user_id FROM $wpdb->pmpro_membership_orders WHERE subscription_transaction_id = '" . esc_sql($customer_id) . "' LIMIT 1");
@@ -312,16 +313,16 @@
312
  return false;
313
  }
314
 
315
- function getUserFromCustomerEvent($event, $status = false, $checkplan = true)
316
  {
317
  //pause here to give PMPro a chance to finish checkout
318
  sleep(PMPRO_STRIPE_WEBHOOK_DELAY);
319
 
320
  global $wpdb;
321
 
322
- $customer_id = $event->data->object->customer;
323
- $subscription_id = $event->data->object->id;
324
- $plan_id = $event->data->object->plan->id;
325
 
326
  //look up the order
327
  $sqlQuery = "SELECT user_id FROM $wpdb->pmpro_membership_orders WHERE (subscription_transaction_id = '" . esc_sql($customer_id) . "' OR subscription_transaction_id = '" . esc_sql($subscription_id) . "') ";
@@ -339,14 +340,14 @@
339
  return false;
340
  }
341
 
342
- function getOldOrderFromInvoiceEvent($event)
343
  {
344
  //pause here to give PMPro a chance to finish checkout
345
  sleep(PMPRO_STRIPE_WEBHOOK_DELAY);
346
 
347
  global $wpdb;
348
 
349
- $customer_id = $event->data->object->customer;
350
 
351
  // no customer passed? we can't cross reference
352
  if(empty($customer_id))
@@ -362,7 +363,7 @@
362
  // let's look up the Stripe subscription_id instead
363
  // unfortunately, the subscription_id is not included in the JSON data from the Stripe event
364
  // so, we must look up the subscription_id from the invoice_id, which IS included in the JSON data from the Stripe event
365
- $invoice_id = $event->data->object->invoice;
366
  $invoice = Stripe_Invoice::retrieve($invoice_id);
367
  $subscription_id = $invoice->subscription;
368
  $old_order_id = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_orders WHERE subscription_transaction_id = '" . $subscription_id . "' AND gateway = 'stripe' ORDER BY timestamp DESC LIMIT 1");
@@ -376,12 +377,12 @@
376
  return false;
377
  }
378
 
379
- function getOrderFromInvoiceEvent($event)
380
  {
381
  //pause here to give PMPro a chance to finish checkout
382
  sleep(PMPRO_STRIPE_WEBHOOK_DELAY);
383
 
384
- $invoice_id = $event->data->object->id;
385
 
386
  $order = new MemberOrder();
387
  $order->getMemberOrderByPaymentTransactionID($invoice_id);
41
  {
42
  try
43
  {
44
+ global $pmpro_stripe_event;
45
+ $pmpro_stripe_event = Stripe_Event::retrieve($event_id);
46
  }
47
  catch(Exception $e)
48
  {
49
  $logstr .= "Could not find an event with ID #" . $event_id . ". " . $e->getMessage();
50
  pmpro_stripeWebhookExit();
51
+ //$pmpro_stripe_event = $post_event; //for testing you may want to assume that the passed in event is legit
52
  }
53
  }
54
 
55
  global $wpdb;
56
 
57
  //real event?
58
+ if(!empty($pmpro_stripe_event->id))
59
  {
60
  //check what kind of event it is
61
+ if($pmpro_stripe_event->type == "charge.succeeded")
62
  {
63
  //do we have this order yet? (check status too)
64
+ $order = getOrderFromInvoiceEvent($pmpro_stripe_event);
65
 
66
  //no? create it
67
  if(empty($order->id))
68
  {
69
  //last order for this subscription
70
+ $old_order = getOldOrderFromInvoiceEvent($pmpro_stripe_event);
71
 
72
  if(empty($old_order))
73
  {
85
  pmpro_stripeWebhookExit();
86
  }
87
 
88
+ $invoice = $pmpro_stripe_event->data->object;
89
 
90
  //alright. create a new order/invoice
91
  $morder = new MemberOrder();
134
  $pmproemail = new PMProEmail();
135
  $pmproemail->sendInvoiceEmail($user, $morder);
136
 
137
+ $logstr .= "Created new order with ID #" . $morder->id . ". Event ID #" . $pmpro_stripe_event->id . ".";
138
 
139
  /*
140
  Checking if there is an update "after next payment" for this user.
208
  }
209
  else
210
  {
211
+ $logstr .= "We've already processed this order with ID #" . $order->id . ". Event ID #" . $pmpro_stripe_event->id . ".";
212
  pmpro_stripeWebhookExit();
213
  }
214
  }
215
+ elseif($pmpro_stripe_event->type == "charge.failed")
216
  {
217
  //last order for this subscription
218
+ $old_order = getOldOrderFromInvoiceEvent($pmpro_stripe_event);
219
  $user_id = $old_order->user_id;
220
  $user = get_userdata($user_id);
221
 
253
  }
254
  else
255
  {
256
+ $logstr .= "Could not find the related subscription for event with ID #" . $pmpro_stripe_event->id . ".";
257
+ if(!empty($pmpro_stripe_event->data->object->customer))
258
+ $logstr .= " Customer ID #" . $pmpro_stripe_event->data->object->customer . ".";
259
  pmpro_stripeWebhookExit();
260
  }
261
  }
262
+ elseif($pmpro_stripe_event->type == "customer.subscription.deleted")
263
  {
264
  //for one of our users? if they still have a membership, notify the admin
265
+ $user = getUserFromCustomerEvent($pmpro_stripe_event, "success", true);
266
  if(!empty($user->ID))
267
  {
268
  do_action("pmpro_stripe_subscription_deleted", $user->ID);
271
  $pmproemail->data = array("body"=>"<p>" . sprintf(__("%s has had their payment subscription cancelled by Stripe. Please check that this user's membership is cancelled on your site if it should be.", "pmpro"), $user->display_name . " (" . $user->user_login . ", " . $user->user_email . ")") . "</p>");
272
  $pmproemail->sendEmail(get_bloginfo("admin_email"));
273
 
274
+ $logstr .= "Subscription deleted for user ID #" . $user->ID . ". Event ID #" . $pmpro_stripe_event->id . ".";
275
  pmpro_stripeWebhookExit();
276
  }
277
  else
278
  {
279
  //check for any user at all
280
+ $user = getUserFromCustomerEvent($pmpro_stripe_event);
281
  if(!empty($user->ID))
282
+ $logstr .= "Stripe tells us a subscription is deleted. This was probably initiated from PMPro and the membership/order is already cancelled. Event ID #" . $pmpro_stripe_event->id . ".";
283
  else
284
+ $logstr .= "Stripe tells us a subscription is deleted, but we could not find a user here for that subscription. Could be a subscription managed by a different app or plugin. Event ID #" . $pmpro_stripe_event->id . ".";
285
  pmpro_stripeWebhookExit();
286
  }
287
  }
295
  pmpro_stripeWebhookExit();
296
  }
297
 
298
+ function getUserFromInvoiceEvent($pmpro_stripe_event)
299
  {
300
  //pause here to give PMPro a chance to finish checkout
301
  sleep(PMPRO_STRIPE_WEBHOOK_DELAY);
302
 
303
  global $wpdb;
304
 
305
+ $customer_id = $pmpro_stripe_event->data->object->customer;
306
 
307
  //look up the order
308
  $user_id = $wpdb->get_var("SELECT user_id FROM $wpdb->pmpro_membership_orders WHERE subscription_transaction_id = '" . esc_sql($customer_id) . "' LIMIT 1");
313
  return false;
314
  }
315
 
316
+ function getUserFromCustomerEvent($pmpro_stripe_event, $status = false, $checkplan = true)
317
  {
318
  //pause here to give PMPro a chance to finish checkout
319
  sleep(PMPRO_STRIPE_WEBHOOK_DELAY);
320
 
321
  global $wpdb;
322
 
323
+ $customer_id = $pmpro_stripe_event->data->object->customer;
324
+ $subscription_id = $pmpro_stripe_event->data->object->id;
325
+ $plan_id = $pmpro_stripe_event->data->object->plan->id;
326
 
327
  //look up the order
328
  $sqlQuery = "SELECT user_id FROM $wpdb->pmpro_membership_orders WHERE (subscription_transaction_id = '" . esc_sql($customer_id) . "' OR subscription_transaction_id = '" . esc_sql($subscription_id) . "') ";
340
  return false;
341
  }
342
 
343
+ function getOldOrderFromInvoiceEvent($pmpro_stripe_event)
344
  {
345
  //pause here to give PMPro a chance to finish checkout
346
  sleep(PMPRO_STRIPE_WEBHOOK_DELAY);
347
 
348
  global $wpdb;
349
 
350
+ $customer_id = $pmpro_stripe_event->data->object->customer;
351
 
352
  // no customer passed? we can't cross reference
353
  if(empty($customer_id))
363
  // let's look up the Stripe subscription_id instead
364
  // unfortunately, the subscription_id is not included in the JSON data from the Stripe event
365
  // so, we must look up the subscription_id from the invoice_id, which IS included in the JSON data from the Stripe event
366
+ $invoice_id = $pmpro_stripe_event->data->object->invoice;
367
  $invoice = Stripe_Invoice::retrieve($invoice_id);
368
  $subscription_id = $invoice->subscription;
369
  $old_order_id = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_orders WHERE subscription_transaction_id = '" . $subscription_id . "' AND gateway = 'stripe' ORDER BY timestamp DESC LIMIT 1");
377
  return false;
378
  }
379
 
380
+ function getOrderFromInvoiceEvent($pmpro_stripe_event)
381
  {
382
  //pause here to give PMPro a chance to finish checkout
383
  sleep(PMPRO_STRIPE_WEBHOOK_DELAY);
384
 
385
+ $invoice_id = $pmpro_stripe_event->data->object->id;
386
 
387
  $order = new MemberOrder();
388
  $order->getMemberOrderByPaymentTransactionID($invoice_id);