Paid Memberships Pro - Version 1.7.15.1

Version Description

  • BUG: Fixed issue where "complete all required fields" was being shown when using Stripe. They are calling the CardType "brand" in their return object, not "type".
  • BUG: Removed code from includes/notifications.php that was deleting the transient used to keep PMPro installs from hitting the PMPro server too often.
  • ENHANCEMENT: Added the "pmpro_checkout_signon_secure" filter so you can tell PMPro to login over http or https in case other plugins (like WordPress MU Domain Mapping) conflict with what should be chosen here.
  • Avoiding some warnings.
Download this release

Release Info

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

Code changes from version 1.1.11 to 1.7.15.1

Files changed (188) hide show
  1. adminpages/addons.php +142 -0
  2. adminpages/addons/hide-admin-bar-from-non-admins.php +32 -0
  3. adminpages/addons/images/pmpro-aweber.gif +0 -0
  4. adminpages/addons/images/pmpro-bbpress.jpg +0 -0
  5. adminpages/addons/images/pmpro-constant-contact.gif +0 -0
  6. adminpages/addons/images/pmpro-email-templates.gif +0 -0
  7. adminpages/addons/images/pmpro-infusionsoft.jpg +0 -0
  8. adminpages/addons/images/pmpro-mailchimp.jpg +0 -0
  9. adminpages/addons/images/pmpro-network.gif +0 -0
  10. adminpages/addons/images/pmpro-post-affiliate-pro.jpg +0 -0
  11. adminpages/addons/images/pmpro-register-helper.gif +0 -0
  12. adminpages/addons/images/pmpro-series.gif +0 -0
  13. adminpages/addons/images/pmpro-woocommerce.gif +0 -0
  14. adminpages/addons/images/pmpro-wp-affiliate-platform.jpg +0 -0
  15. adminpages/addons/images/wp-bouncer.gif +0 -0
  16. adminpages/addons/pmpro-addon-packages.php +30 -0
  17. adminpages/addons/pmpro-affiliates.php +30 -0
  18. adminpages/addons/pmpro-aweber.php +31 -0
  19. adminpages/addons/pmpro-bbpress.php +31 -0
  20. adminpages/addons/pmpro-constant-contact.php +31 -0
  21. adminpages/addons/pmpro-disable-emails.php +28 -0
  22. adminpages/addons/pmpro-email-templates.php +31 -0
  23. adminpages/addons/pmpro-expiration.php +30 -0
  24. adminpages/addons/pmpro-freeaddress.php +30 -0
  25. adminpages/addons/pmpro-infusionsoft.php +31 -0
  26. adminpages/addons/pmpro-international-addresses.php +31 -0
  27. adminpages/addons/pmpro-level-cost-text.php +30 -0
  28. adminpages/addons/pmpro-mailchimp.php +31 -0
  29. adminpages/addons/pmpro-network-subsite.php +31 -0
  30. adminpages/addons/pmpro-network.php +31 -0
  31. adminpages/addons/pmpro-post-affiliate-pro.php +31 -0
  32. adminpages/addons/pmpro-register-helper.php +31 -0
  33. adminpages/addons/pmpro-require-code-to-register.php +28 -0
  34. adminpages/addons/pmpro-series.php +31 -0
  35. adminpages/addons/pmpro-shipping.php +31 -0
  36. adminpages/addons/pmpro-user-pages.php +30 -0
  37. adminpages/addons/pmpro-woocommerce.php +31 -0
  38. adminpages/addons/pmpro-wp-affiliate.php +31 -0
  39. adminpages/addons/tml.php +32 -0
  40. adminpages/addons/wp-bouncer.php +31 -0
  41. adminpages/admin_footer.php +2 -0
  42. adminpages/admin_header.php +156 -0
  43. adminpages/advancedsettings.php +374 -0
  44. adminpages/dashboard.php +127 -0
  45. adminpages/discountcodes.php +664 -0
  46. adminpages/emailsettings.php +181 -0
  47. adminpages/functions.php +219 -0
  48. adminpages/membershiplevels.php +615 -1016
  49. adminpages/memberslist-csv.php +215 -58
  50. adminpages/memberslist.php +238 -126
  51. adminpages/orders-csv.php +297 -0
  52. adminpages/orders.php +996 -0
  53. adminpages/pagesettings.php +257 -0
  54. adminpages/paymentsettings.php +540 -0
  55. adminpages/reports.php +62 -0
  56. adminpages/reports/login.php +412 -0
  57. adminpages/reports/memberships.php +660 -0
  58. adminpages/reports/sales.php +406 -0
  59. classes/class.memberorder.php +394 -1101
  60. classes/class.pmproemail.php +536 -56
  61. classes/gateways/class.pmprogateway.php +220 -0
  62. classes/gateways/class.pmprogateway_authorizenet.php +949 -0
  63. classes/gateways/class.pmprogateway_braintree.php +466 -0
  64. classes/gateways/class.pmprogateway_check.php +208 -0
  65. classes/gateways/class.pmprogateway_cybersource.php +764 -0
  66. classes/gateways/class.pmprogateway_payflowpro.php +448 -0
  67. classes/gateways/class.pmprogateway_paypal.php +456 -0
  68. classes/gateways/class.pmprogateway_paypalexpress.php +400 -0
  69. classes/gateways/class.pmprogateway_paypalstandard.php +301 -0
  70. classes/gateways/class.pmprogateway_stripe.php +428 -0
  71. classes/gateways/class.pmprogateway_twocheckout.php +144 -0
  72. css/admin-rtl.css +63 -0
  73. css/admin.css +97 -43
  74. css/frontend-rtl.css +111 -0
  75. css/frontend.css +174 -96
  76. email/admin_change.html +1 -1
  77. email/admin_change_admin.html +5 -0
  78. email/billing.html +1 -4
  79. email/billing_admin.html +17 -0
  80. email/billing_failure.html +1 -5
  81. email/billing_failure_admin.html +1 -5
  82. email/cancel.html +1 -1
  83. email/cancel_admin.html +8 -0
  84. email/checkout_check.html +17 -0
  85. email/checkout_check_admin.html +17 -0
  86. email/checkout_express.html +14 -0
  87. email/checkout_express_admin.html +14 -0
  88. email/checkout_free.html +1 -0
  89. email/checkout_free_admin.html +8 -0
  90. email/checkout_freetrial.html +2 -4
  91. email/checkout_freetrial_admin.html +19 -0
  92. email/checkout_paid.html +3 -5
  93. email/checkout_paid_admin.html +23 -0
  94. email/checkout_trial.html +4 -5
  95. email/checkout_trial_admin.html +23 -0
  96. email/credit_card_expiring.html +13 -0
  97. email/invoice.html +2 -5
  98. email/membership_expired.html +7 -0
  99. email/membership_expiring.html +6 -0
  100. email/trial_ending.html +2 -14
  101. images/Paid-Memberships-Pro.png +0 -0
  102. images/Paid-Memberships-Pro_watermark.png +0 -0
  103. images/bg_grad-chrome.gif +0 -0
  104. images/bg_grad-grey.gif +0 -0
  105. images/icon-pmproadmin16-sprite.png +0 -0
  106. images/icon-pmproadmin16-sprite_2x.png +0 -0
  107. images/icon-pmproadmin32.png +0 -0
  108. images/icon-pmproadmin32_2x.png +0 -0
  109. includes/adminpages.php +226 -0
  110. includes/cleanup.php +40 -0
  111. includes/content.php +437 -0
  112. includes/countries.php +259 -0
  113. includes/currencies.php +69 -0
  114. includes/email.php +120 -0
  115. includes/filters.php +150 -0
  116. includes/functions.php +1795 -762
  117. includes/https.php +185 -0
  118. includes/init.php +240 -0
  119. includes/lib/Braintree/Braintree.php +172 -0
  120. includes/lib/Braintree/Braintree/AddOn.php +15 -0
  121. includes/lib/Braintree/Braintree/Address.php +352 -0
  122. includes/lib/Braintree/Braintree/Collection.php +159 -0
  123. includes/lib/Braintree/Braintree/Configuration.php +346 -0
  124. includes/lib/Braintree/Braintree/CreditCard.php +591 -0
  125. includes/lib/Braintree/Braintree/CreditCardVerification.php +41 -0
  126. includes/lib/Braintree/Braintree/CreditCardVerificationSearch.php +34 -0
  127. includes/lib/Braintree/Braintree/Customer.php +562 -0
  128. includes/lib/Braintree/Braintree/CustomerSearch.php +31 -0
  129. includes/lib/Braintree/Braintree/Descriptor.php +4 -0
  130. includes/lib/Braintree/Braintree/Digest.php +59 -0
  131. includes/lib/Braintree/Braintree/Discount.php +15 -0
  132. includes/lib/Braintree/Braintree/EqualityNode.php +10 -0
  133. includes/lib/Braintree/Braintree/Error/Codes.php +206 -0
  134. includes/lib/Braintree/Braintree/Error/ErrorCollection.php +118 -0
  135. includes/lib/Braintree/Braintree/Error/Validation.php +64 -0
  136. includes/lib/Braintree/Braintree/Error/ValidationErrorCollection.php +135 -0
  137. includes/lib/Braintree/Braintree/Exception.php +20 -0
  138. includes/lib/Braintree/Braintree/Exception/Authentication.php +21 -0
  139. includes/lib/Braintree/Braintree/Exception/Authorization.php +23 -0
  140. includes/lib/Braintree/Braintree/Exception/Configuration.php +20 -0
  141. includes/lib/Braintree/Braintree/Exception/DownForMaintenance.php +20 -0
  142. includes/lib/Braintree/Braintree/Exception/ForgedQueryString.php +23 -0
  143. includes/lib/Braintree/Braintree/Exception/InvalidSignature.php +5 -0
  144. includes/lib/Braintree/Braintree/Exception/NotFound.php +20 -0
  145. includes/lib/Braintree/Braintree/Exception/SSLCaFileNotFound.php +20 -0
  146. includes/lib/Braintree/Braintree/Exception/SSLCertificate.php +20 -0
  147. includes/lib/Braintree/Braintree/Exception/ServerError.php +20 -0
  148. includes/lib/Braintree/Braintree/Exception/Unexpected.php +21 -0
  149. includes/lib/Braintree/Braintree/Exception/UpgradeRequired.php +12 -0
  150. includes/lib/Braintree/Braintree/Exception/ValidationsFailed.php +21 -0
  151. includes/lib/Braintree/Braintree/Http.php +99 -0
  152. includes/lib/Braintree/Braintree/Instance.php +70 -0
  153. includes/lib/Braintree/Braintree/IsNode.php +22 -0
  154. includes/lib/Braintree/Braintree/KeyValueNode.php +22 -0
  155. includes/lib/Braintree/Braintree/Modification.php +23 -0
  156. includes/lib/Braintree/Braintree/MultipleValueNode.php +37 -0
  157. includes/lib/Braintree/Braintree/MultipleValueOrTextNode.php +46 -0
  158. includes/lib/Braintree/Braintree/PartialMatchNode.php +16 -0
  159. includes/lib/Braintree/Braintree/Plan.php +55 -0
  160. includes/lib/Braintree/Braintree/RangeNode.php +38 -0
  161. includes/lib/Braintree/Braintree/ResourceCollection.php +148 -0
  162. includes/lib/Braintree/Braintree/Result/CreditCardVerification.php +86 -0
  163. includes/lib/Braintree/Braintree/Result/Error.php +107 -0
  164. includes/lib/Braintree/Braintree/Result/Successful.php +78 -0
  165. includes/lib/Braintree/Braintree/SettlementBatchSummary.php +74 -0
  166. includes/lib/Braintree/Braintree/Subscription.php +256 -0
  167. includes/lib/Braintree/Braintree/SubscriptionSearch.php +64 -0
  168. includes/lib/Braintree/Braintree/SubscriptionStatus.php +0 -0
  169. includes/lib/Braintree/Braintree/Test/CreditCardNumbers.php +76 -0
  170. includes/lib/Braintree/Braintree/Test/TransactionAmounts.php +24 -0
  171. includes/lib/Braintree/Braintree/TextNode.php +10 -0
  172. includes/lib/Braintree/Braintree/Transaction.php +664 -0
  173. includes/lib/Braintree/Braintree/Transaction/AddressDetails.php +32 -0
  174. includes/lib/Braintree/Braintree/Transaction/CreditCardDetails.php +43 -0
  175. includes/lib/Braintree/Braintree/Transaction/CustomerDetails.php +29 -0
  176. includes/lib/Braintree/Braintree/Transaction/StatusDetails.php +25 -0
  177. includes/lib/Braintree/Braintree/Transaction/SubscriptionDetails.php +22 -0
  178. includes/lib/Braintree/Braintree/TransactionSearch.php +124 -0
  179. includes/lib/Braintree/Braintree/TransparentRedirect.php +327 -0
  180. includes/lib/Braintree/Braintree/Util.php +290 -0
  181. includes/lib/Braintree/Braintree/Version.php +39 -0
  182. includes/lib/Braintree/Braintree/WebhookNotification.php +66 -0
  183. includes/lib/Braintree/Braintree/WebhookTesting.php +52 -0
  184. includes/lib/Braintree/Braintree/Xml.php +43 -0
  185. includes/lib/Braintree/Braintree/Xml/Generator.php +144 -0
  186. includes/lib/Braintree/Braintree/Xml/Parser.php +179 -0
  187. includes/lib/Braintree/ssl/sandbox_braintreegateway_com.ca.crt +19 -0
  188. includes/lib/Braintree/ssl/www_braintreegateway_com.ca.crt +137 -0
adminpages/addons.php ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //only admins can get this
3
+ if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_addons")))
4
+ {
5
+ die(__("You do not have permissions to perform this action.", "pmpro"));
6
+ }
7
+
8
+ global $wpdb, $msg, $msgt, $pmpro_addons;
9
+
10
+ /*
11
+ Addon lists
12
+ */
13
+ $pmpro_addon_lists = array(
14
+ 'repo' => array('Plugins in the WordPress Repository', 'These official PMPro plugins are available in the WordPress repository and can be installed through Plugins --> Add New.'),
15
+ 'thirdparty' => array('Third-party Integration', 'These official PMPro plugins integrate with specific third-party tools and software.'),
16
+ 'recommended' => array('Recommended Plugins', 'These plugins are not developed by the PMPro team, but are recommended for sites running PMPro.'),
17
+ 'github' => array('Plugins on GitHub', 'These official PMPro plugins must be downloaded from GitHub and installed through Plugins --> Add New --> Upload, then activated. These plugins cannot be automatically updated and may require more developer input.'),
18
+ 'gists' => array('Code Gists', 'These are bits of code that generally must be added to your active theme\'s functions.php file or included in a custom plugin. Most gists require customization and are recommended for developers only.')
19
+ );
20
+
21
+ /*
22
+ Function to add an addon
23
+ */
24
+ function pmpro_add_addon($list, $addon)
25
+ {
26
+ global $pmpro_addons;
27
+
28
+ //make sure we have the base array
29
+ if(empty($pmpro_addons))
30
+ $pmpro_addons = array();
31
+
32
+ //make sure we have an array for the list
33
+ if(empty($pmpro_addons[$list]))
34
+ $pmpro_addons[$list] = array();
35
+
36
+ //add addon to list
37
+ $pmpro_addons[$list][] = $addon;
38
+ }
39
+
40
+ /*
41
+ Load All Addons
42
+ */
43
+ $pmpro_addons_dir = dirname(__FILE__) . "/../adminpages/addons/";
44
+ $cwd = getcwd();
45
+ chdir($pmpro_addons_dir);
46
+ $count = 0;
47
+ foreach (glob("*.php") as $filename)
48
+ {
49
+ $count++;
50
+ require_once($filename);
51
+ }
52
+ chdir($cwd);
53
+
54
+ require_once(dirname(__FILE__) . "/admin_header.php");
55
+ ?>
56
+
57
+ <h2>Add Ons</h2>
58
+ <ul id="addon-filters" class="subsubsub">
59
+ <li id="addon-filters-all"><a href="javascript:void(0);" class="current all tab">All</a> <span>(<?php echo $count;?>)</span></li>
60
+ <?php foreach($pmpro_addon_lists as $list => $list_info) { ?>
61
+ <li id="addon-filters-<?php echo $list;?>"> | <a href="javascript:void(0);>" class="tab"><?php echo $list_info[0];?></a> <span>(<?php echo count($pmpro_addons[$list]);?>)</span></li>
62
+ <?php } ?>
63
+ </ul>
64
+
65
+ <?php foreach($pmpro_addon_lists as $list => $list_info) { ?>
66
+ <div id="pmpro-<?php echo $list;?>" class="pmpro-addon-list widgets-holder-wrap">
67
+
68
+ <h3 class="section-title"><?php echo $list_info[0];?></h3>
69
+ <p class="description"><?php echo $list_info[1];?></p>
70
+ <br class="clear" />
71
+
72
+ <div id="addons-list-<?php echo $list;?>" class="addon-list">
73
+
74
+ <?php foreach($pmpro_addons[$list] as $slug => $addon) { ?>
75
+ <div id="addon-<?php echo $slug;?>" class="widget <?php if($addon['enabled']) echo "enabled"; else echo "disabled";?>">
76
+ <div class="widget-top">
77
+ <div class="widget-title">
78
+ <h4>
79
+ <span class="status-label"><?php if($addon['enabled']) echo __("Enabled", "pmpro"); else echo __("Disabled", "pmpro");?></span>
80
+ <span class="title"><?php echo $addon['title'];?></span>
81
+ <span class="version pmpro_tag-grey"><?php echo $addon['version'];?></span>
82
+ <span class="in-widget-title"></span>
83
+ </h4>
84
+ </div> <!-- end widget-title -->
85
+ </div> <!-- end widget-top -->
86
+ <div class="widget-inside">
87
+ <?php call_user_func($addon['widget'], $addon);?>
88
+ </div> <!-- end addon-inside -->
89
+ </div> <!-- end widget -->
90
+ <?php } ?>
91
+
92
+ <br class="clear" />
93
+ </div> <!-- end addon-list -->
94
+
95
+ </div> <!-- end pmpro-<?php echo $list;?> -->
96
+ <?php } ?>
97
+
98
+ <script>
99
+ //tabs
100
+ jQuery(document).ready(function() {
101
+ jQuery('#addon-filters a.tab').click(function() {
102
+ //which tab?
103
+ var tab = jQuery(this).parent().attr('id').replace('addon-filters-', '');
104
+
105
+ //un select tabs
106
+ jQuery('#addon-filters a.tab').removeClass('current');
107
+
108
+ //select this tab
109
+ jQuery('#addon-filters-'+tab+' a').addClass('current');
110
+
111
+ //show all?
112
+ if(tab == 'all')
113
+ jQuery('div.pmpro-addon-list').show();
114
+ else
115
+ {
116
+ //hide all
117
+ jQuery('div.pmpro-addon-list').hide();
118
+
119
+ //show this one
120
+ jQuery('#pmpro-'+tab).show();
121
+ }
122
+ });
123
+ });
124
+
125
+ //resize addon boxes
126
+ jQuery(document).ready(function() {
127
+ jQuery('.addon-list').each(function() {
128
+ //what's the tallest p in the list?
129
+ var tallest = 32;
130
+ jQuery(this).find('div.info p').each(function() {
131
+ tallest = Math.max(tallest, jQuery(this).height());
132
+ });
133
+
134
+ //set all p's to match
135
+ jQuery(this).find('div.info p').css('height', tallest);
136
+ });
137
+ });
138
+ </script>
139
+
140
+ <?php
141
+ require_once(dirname(__FILE__) . "/admin_footer.php");
142
+ ?>
adminpages/addons/hide-admin-bar-from-non-admins.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: Hide Admin Bar From Non-Admins
4
+ Slug: hide-admin-bar-from-non-admins
5
+ */
6
+ pmpro_add_addon('repo', array(
7
+ 'title' => 'Hide Admin Bar From Non-Admins',
8
+ 'version' => '1.0',
9
+ 'widget' => 'pmpro_addon_hide_admin_bar_from_non_admins_widget',
10
+ 'enabled' => function_exists('habfna_disable_admin_bar')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_hide_admin_bar_from_non_admins_widget($addon)
15
+ {
16
+ ?>
17
+ <div class="info">
18
+ <p>Perfect for sites where there is only one admin who needs access to the dashboard and the admin bar. When activated only administrators will see the admin bar.</p>
19
+ <div class="actions">
20
+ <form method="post" name="component-actions" action="">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="<?php echo admin_url("plugins.php");?>" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../hide-admin-bar-from-non-admins/hide-admin-bar-from-non-admins.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=hide-admin-bar-from-non-admins/hide-admin-bar-from-non-admins.php'), 'activate-plugin_hide-admin-bar-from-non-admins/hide-admin-bar-from-non-admins.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="<?php echo wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=hide-admin-bar-from-non-admins'), 'install-plugin_hide-admin-bar-from-non-admins'); ?>" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </form>
29
+ </div>
30
+ </div> <!-- end info -->
31
+ <?php
32
+ }
adminpages/addons/images/pmpro-aweber.gif ADDED
Binary file
adminpages/addons/images/pmpro-bbpress.jpg ADDED
Binary file
adminpages/addons/images/pmpro-constant-contact.gif ADDED
Binary file
adminpages/addons/images/pmpro-email-templates.gif ADDED
Binary file
adminpages/addons/images/pmpro-infusionsoft.jpg ADDED
Binary file
adminpages/addons/images/pmpro-mailchimp.jpg ADDED
Binary file
adminpages/addons/images/pmpro-network.gif ADDED
Binary file
adminpages/addons/images/pmpro-post-affiliate-pro.jpg ADDED
Binary file
adminpages/addons/images/pmpro-register-helper.gif ADDED
Binary file
adminpages/addons/images/pmpro-series.gif ADDED
Binary file
adminpages/addons/images/pmpro-woocommerce.gif ADDED
Binary file
adminpages/addons/images/pmpro-wp-affiliate-platform.jpg ADDED
Binary file
adminpages/addons/images/wp-bouncer.gif ADDED
Binary file
adminpages/addons/pmpro-addon-packages.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Addon Packages
4
+ Slug: pmpro-addon-packages
5
+ */
6
+ pmpro_add_addon('github', array(
7
+ 'title' => 'PMPro Addon Packages',
8
+ 'version' => '.4.3',
9
+ 'widget' => 'pmpro_addon_pmpro_addon_packages_widget',
10
+ 'enabled' => function_exists('pmproap_post_meta')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_addon_packages_widget($addon)
15
+ {
16
+ ?>
17
+ <div class="info">
18
+ <p>Sell access to individual pages or posts for a flat fee. This is a workaround if you would like to allow multiple membership levels per user.</p>
19
+ <div class="actions">
20
+ <?php if($addon['enabled']) { ?>
21
+ <a href="https://github.com/strangerstudios/pmpro-addon-packages/blob/master/readme.txt" class="button">Enabled</a>
22
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-addon-packages/pmpro-addon-packages.php")) { ?>
23
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-addon-packages/pmpro-addon-packages.php'), 'activate-plugin_pmpro-addon-packages/pmpro-addon-packages.php')?>" class="button button-primary">Activate</a>
24
+ <?php } else { ?>
25
+ <a href="https://www.paidmembershipspro.com/wp-content/uploads/plugins/pmpro-addon-packages.zip" class="button button-primary">Download</a>
26
+ <?php } ?>
27
+ </div>
28
+ </div> <!-- end info -->
29
+ <?php
30
+ }
adminpages/addons/pmpro-affiliates.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Affiliates
4
+ Slug: pmpro-affiliates
5
+ */
6
+ pmpro_add_addon('github', array(
7
+ 'title' => 'PMPro Affiliates',
8
+ 'version' => '.2.4',
9
+ 'widget' => 'pmpro_addon_pmpro_affiliates_widget',
10
+ 'enabled' => function_exists('pmpro_affiliates_dependencies')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_affiliates_widget($addon)
15
+ {
16
+ ?>
17
+ <div class="info">
18
+ <p>Lightweight Affiliate system. Create affiliate accounts and codes; tracks checkouts by affiliate account.</p>
19
+ <div class="actions">
20
+ <?php if($addon['enabled']) { ?>
21
+ <a href="https://github.com/strangerstudios/pmpro-affiliates/blob/master/readme.txt" class="button">Enabled</a>
22
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-affiliates/pmpro-affiliates.php")) { ?>
23
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-affiliates/pmpro-affiliates.php'), 'activate-plugin_pmpro-affiliates/pmpro-affiliates.php')?>" class="button button-primary">Activate</a>
24
+ <?php } else { ?>
25
+ <a href="http://www.paidmembershipspro.com/wp-content/uploads/plugins/pmpro-affiliates.zip" class="button button-primary">Download</a>
26
+ <?php } ?>
27
+ </div>
28
+ </div> <!-- end info -->
29
+ <?php
30
+ }
adminpages/addons/pmpro-aweber.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro AWeber Integration
4
+ Slug: pmpro-aweber
5
+ */
6
+ pmpro_add_addon('thirdparty', array(
7
+ 'title' => 'PMPro AWeber Integration',
8
+ 'version' => '1.0',
9
+ 'widget' => 'pmpro_addon_pmpro_aweber_widget',
10
+ 'enabled' => function_exists('pmproaw_init')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_aweber_widget($addon)
15
+ {
16
+ ?>
17
+ <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-aweber.gif" />
18
+ <div class="info">
19
+ <p>Integrate User Registrations with AWeber. Adds members to lists based on their membership level. (Note: works without PMPro as well.)</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="<?php echo admin_url("plugins.php");?>" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-aweber/pmpro-aweber.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-aweber/pmpro-aweber.php'), 'activate-plugin_pmpro-aweber/pmpro-aweber.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="<?php echo wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=pmpro-aweber'), 'install-plugin_pmpro-aweber'); ?>" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/pmpro-bbpress.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro bbPress
4
+ Slug: pmpro-bbpress
5
+ */
6
+ pmpro_add_addon('repo', array(
7
+ 'title' => 'PMPro bbPress',
8
+ 'version' => '1.0.1',
9
+ 'widget' => 'pmpro_addon_pmpro_bbpress_widget',
10
+ 'enabled' => function_exists('pmprobbp_add_meta_box')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_bbpress_widget($addon)
15
+ {
16
+ ?>
17
+ <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-bbpress.jpg" />
18
+ <div class="info">
19
+ <p>Locking down bbPress Forums by Membership Level and Forum ID.</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="<?php echo admin_url("plugins.php");?>" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-bbpress/pmpro-bbpress.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-bbpress/pmpro-bbpress.php'), 'activate-plugin_pmpro-bbpress/pmpro-bbpress.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="<?php echo wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=pmpro-bbpress'), 'install-plugin_pmpro-bbpress'); ?>" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/pmpro-constant-contact.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Constant Contact Integration
4
+ Slug: pmpro-constant-contact
5
+ */
6
+ pmpro_add_addon('thirdparty', array(
7
+ 'title' => 'PMPro Constant Contact Integration',
8
+ 'version' => '1.0',
9
+ 'widget' => 'pmpro_addon_pmpro_constant_contact_widget',
10
+ 'enabled' => function_exists('pmprocc_init')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_constant_contact_widget($addon)
15
+ {
16
+ ?>
17
+ <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-constant-contact.gif" />
18
+ <div class="info">
19
+ <p>Integrate User Registrations with Constant Contact . Adds members to lists based on their membership level. (Note: works without PMPro as well.)</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="<?php echo admin_url("plugins.php");?>" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-constant-contact/pmpro-constant-contact.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-constant-contact/pmpro-constant-contact.php'), 'activate-plugin_pmpro-constant-contact/pmpro-constant-contact.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="<?php echo wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=pmpro-constant-contact'), 'install-plugin_pmpro-constant-contact'); ?>" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/pmpro-disable-emails.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Disable PMPro Emails
4
+ Slug: pmpro-disable-emails
5
+ */
6
+ pmpro_add_addon('gists', array(
7
+ 'title' => 'PMPro Disable Emails',
8
+ 'version' => '.1',
9
+ 'widget' => 'pmpro_addon_pmpro_disable_emails_widget',
10
+ 'enabled' => function_exists('dae_pmpro_email_recipient')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_disable_emails_widget($addon)
15
+ {
16
+ ?>
17
+ <div class="info">
18
+ <p>Disable all or specific emails sent by the PMPro plugin.</p>
19
+ <div class="actions">
20
+ <?php if($addon['enabled']) { ?>
21
+ <a target="_blank" href="https://gist.github.com/strangerstudios/3667545" class="button">Enabled</a>
22
+ <?php } else { ?>
23
+ <a target="_blank" href="https://gist.github.com/strangerstudios/3667545" class="button button-primary">View Gist</a>
24
+ <?php } ?>
25
+ </div>
26
+ </div> <!-- end info -->
27
+ <?php
28
+ }
adminpages/addons/pmpro-email-templates.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Email Templates Editor
4
+ Slug: pmpro-email-templates-addon
5
+ */
6
+ pmpro_add_addon('repo', array(
7
+ 'title' => 'PMPro Email Templates',
8
+ 'version' => '.5.2',
9
+ 'widget' => 'pmpro_addon_email_templates_widget',
10
+ 'enabled' => function_exists('pmproet_scripts')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_email_templates_widget($addon)
15
+ {
16
+ ?>
17
+ <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-email-templates.gif" />
18
+ <div class="info">
19
+ <p>Easily edit system-generated Email Templates from the WordPress admin.</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="http://wordpress.org/plugins/pmpro-email-templates-addon/" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-email-templates-addon/pmpro-email-templates.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-email-templates-addon/pmpro-email-templates.php'), 'activate-plugin_pmpro-email-templates-addon/pmpro-email-templates.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="<?php echo wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=pmpro-email-templates-addon'), 'install-plugin_pmpro-email-templates-addon'); ?>" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/pmpro-expiration.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Expiration Date
4
+ Slug: pmpro-expiration
5
+ */
6
+ pmpro_add_addon('github', array(
7
+ 'title' => 'PMPro Set Expiration Dates',
8
+ 'version' => '.1.1',
9
+ 'widget' => 'pmpro_addon_pmpro_expiration_widget',
10
+ 'enabled' => function_exists('pmprosed_pmpro_checkout_level')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_expiration_widget($addon)
15
+ {
16
+ ?>
17
+ <div class="info">
18
+ <p>Set a specific expiration date (e.g. 2013-12-31) for a PMPro membership level or discount code.</p>
19
+ <div class="actions">
20
+ <?php if($addon['enabled']) { ?>
21
+ <a href="https://github.com/strangerstudios/pmpro-set-expiration-dates/blob/master/readme.txt" class="button">Enabled</a>
22
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-set-expiration-dates/pmpro-set-expiration-dates.php")) { ?>
23
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-set-expiration-dates/pmpro-set-expiration-dates.php'), 'activate-plugin_pmpro-set-expiration-dates/pmpro-set-expiration-dates.php')?>" class="button button-primary">Activate</a>
24
+ <?php } else { ?>
25
+ <a href="http://www.paidmembershipspro.com/wp-content/uploads/plugins/pmpro-set-expiration-dates.zip" class="button button-primary">Download</a>
26
+ <?php } ?>
27
+ </div>
28
+ </div> <!-- end info -->
29
+ <?php
30
+ }
adminpages/addons/pmpro-freeaddress.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Require Name and Address for Free Level
4
+ Slug: pmpro-freerequire
5
+ */
6
+ pmpro_add_addon('github', array(
7
+ 'title' => 'PMPro Require Name/Address for Free Level',
8
+ 'version' => '.2',
9
+ 'widget' => 'pmpro_addon_pmpro_freerequire_widget',
10
+ 'enabled' => function_exists('my_pmpro_checkout_boxes_require_address')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_freerequire_widget($addon)
15
+ {
16
+ ?>
17
+ <div class="info">
18
+ <p>Require name/address for free Membership Level checkout.</p>
19
+ <div class="actions">
20
+ <?php if($addon['enabled']) { ?>
21
+ <a href="https://github.com/strangerstudios/pmpro-address-for-free-levels" class="button">Enabled</a>
22
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-address-for-free-levels/pmpro-address-for-free-levels.php")) { ?>
23
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-address-for-free-levels/pmpro-address-for-free-levels.php'), 'activate-plugin_pmpro-address-for-free-levels/pmpro-address-for-free-levels.php')?>" class="button button-primary">Activate</a>
24
+ <?php } else { ?>
25
+ <a href="http://www.paidmembershipspro.com/wp-content/uploads/plugins/pmpro-address-for-free-levels.zip" class="button button-primary">Download</a>
26
+ <?php } ?>
27
+ </div>
28
+ </div> <!-- end info -->
29
+ <?php
30
+ }
adminpages/addons/pmpro-infusionsoft.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Infusionsoft Integration
4
+ Slug: pmpro-infusionsoft
5
+ */
6
+ pmpro_add_addon('thirdparty', array(
7
+ 'title' => 'PMPro Infusionsoft Integration',
8
+ 'version' => '1.2',
9
+ 'widget' => 'pmpro_addon_pmpro_infusionsoft_widget',
10
+ 'enabled' => function_exists('pmprois_init')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_infusionsoft_widget($addon)
15
+ {
16
+ ?>
17
+ <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-infusionsoft.jpg" />
18
+ <div class="info">
19
+ <p>Integrate with Infusionsoft. Add members to email lists (groups, tags) based on their membership level. (Note: works without PMPro as well.)</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="<?php echo admin_url("plugins.php");?>" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-infusionsoft/pmpro-infusionsoft.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-infusionsoft/pmpro-infusionsoft.php'), 'activate-plugin_pmpro-infusionsoft/pmpro-infusionsoft.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="<?php echo wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=pmpro-infusionsoft'), 'install-plugin_pmpro-infusionsoft'); ?>" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/pmpro-international-addresses.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro International Addresses
4
+ Slug: pmpro-international-addresses
5
+ */
6
+ pmpro_add_addon('github', array(
7
+ 'title' => 'PMPro International Addresses',
8
+ 'version' => '.2.2',
9
+ 'widget' => 'pmpro_addon_pmpro_international_addresses_widget',
10
+ 'enabled' => function_exists('pmproia_pmpro_international_addresses')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_international_addresses_widget($addon)
15
+ {
16
+ ?>
17
+ <?php /* <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-international-addresses.jpg" /> */ ?>
18
+ <div class="info">
19
+ <p>Adds long form addresses to the PMPro checkout.</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="https://github.com/strangerstudios/pmpro-international-addresses/" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-international-addresses/pmpro-international-addresses.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-international-addresses/pmpro-international-addresses.php'), 'activate-plugin_pmpro-international-addresses/pmpro-international-addresses.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="http://www.paidmembershipspro.com/wp-content/uploads/plugins/pmpro-international-addresses.zip" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/pmpro-level-cost-text.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Custom Level Cost Text
4
+ Slug: pmpro-level-cost-text
5
+ */
6
+ pmpro_add_addon('github', array(
7
+ 'title' => 'PMPro Level Cost Text',
8
+ 'version' => '.2',
9
+ 'widget' => 'pmpro_addon_pmpro_level_cost_text_widget',
10
+ 'enabled' => function_exists('pclct_pmpro_discount_code_after_level_settings')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_level_cost_text_widget($addon)
15
+ {
16
+ ?>
17
+ <div class="info">
18
+ <p>Adds a "level cost text" field to PMPro Membership Levels and Discount Codes to allow you to override the automatically generated level cost text PMPro provides.</p>
19
+ <div class="actions">
20
+ <?php if($addon['enabled']) { ?>
21
+ <a href="https://github.com/strangerstudios/pmpro-level-cost-text/blob/master/readme.txt" class="button">Enabled</a>
22
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-level-cost-text/pmpro-level-cost-text.php")) { ?>
23
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-level-cost-text/pmpro-level-cost-text.php'), 'activate-plugin_pmpro-level-cost-text/pmpro-level-cost-text.php')?>" class="button button-primary">Activate</a>
24
+ <?php } else { ?>
25
+ <a href="http://www.paidmembershipspro.com/wp-content/uploads/plugins/pmpro-level-cost-text.zip" class="button button-primary">Download</a>
26
+ <?php } ?>
27
+ </div>
28
+ </div> <!-- end info -->
29
+ <?php
30
+ }
adminpages/addons/pmpro-mailchimp.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro MailChimp Integration
4
+ Slug: pmpro-mailchimp
5
+ */
6
+ pmpro_add_addon('thirdparty', array(
7
+ 'title' => 'PMPro MailChimp Integration',
8
+ 'version' => '1.0',
9
+ 'widget' => 'pmpro_addon_pmpro_mailchimp_widget',
10
+ 'enabled' => function_exists('pmpromc_init')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_mailchimp_widget($addon)
15
+ {
16
+ ?>
17
+ <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-mailchimp.jpg" />
18
+ <div class="info">
19
+ <p>Integrate User Registrations with Mailchimp. Adds members to lists based on their membership level. (Note: works without PMPro as well.)</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="<?php echo admin_url("plugins.php");?>" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-mailchimp/pmpro-mailchimp.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-mailchimp/pmpro-mailchimp.php'), 'activate-plugin_pmpro-mailchimp/pmpro-mailchimp.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="<?php echo wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=pmpro-mailchimp'), 'install-plugin_pmpro-mailchimp'); ?>" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/pmpro-network-subsite.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Network
4
+ Slug: pmpro-network-subsite
5
+ */
6
+ pmpro_add_addon('github', array(
7
+ 'title' => 'PMPro Network Subsite Helper',
8
+ 'version' => '.2',
9
+ 'widget' => 'pmpro_addon_pmpro_network_subsite_widget',
10
+ 'enabled' => function_exists('pmpron_subsite_activated_plugin')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_network_subsite_widget($addon)
15
+ {
16
+ ?>
17
+ <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-network.gif" />
18
+ <div class="info">
19
+ <p>Have network subsites use membership data from a "main" site to handle access restrictions.</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="https://github.com/strangerstudios/pmpro-network-subsite" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-network-subsite/pmpro-network-subsite.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-network-subsite/pmpro-network-subsite.php'), 'activate-plugin_pmpro-network-subsite/pmpro-network-subsite.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="http://www.paidmembershipspro.com/wp-content/uploads/plugins/pmpro-network-subsite.zip" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/pmpro-network.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Network
4
+ Slug: pmpro-network
5
+ */
6
+ pmpro_add_addon('github', array(
7
+ 'title' => 'PMPro Network',
8
+ 'version' => '.3.1',
9
+ 'widget' => 'pmpro_addon_pmpro_network_widget',
10
+ 'enabled' => function_exists('pmpron_new_blogs_settings')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_network_widget($addon)
15
+ {
16
+ ?>
17
+ <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-network.gif" />
18
+ <div class="info">
19
+ <p>Allow users to checkout for a membership to create a site on your WordPress multisite network.</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="https://github.com/strangerstudios/pmpro-network/blob/master/readme.txt" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-network/pmpro-network.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-network/pmpro-network.php'), 'activate-plugin_pmpro-network/pmpro-network.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="http://www.paidmembershipspro.com/wp-content/uploads/plugins/pmpro-network.zip" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/pmpro-post-affiliate-pro.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Post Affiliate Pro Integration
4
+ Slug: pmpro-post-affiliate-pro
5
+ */
6
+ pmpro_add_addon('thirdparty', array(
7
+ 'title' => 'PMPro Post Affiliate Pro Integration',
8
+ 'version' => '.2.1.1',
9
+ 'widget' => 'pmpro_addon_pmpro_post_affiliate_pro_widget',
10
+ 'enabled' => function_exists('pap_pmpro_track_sale')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_post_affiliate_pro_widget($addon)
15
+ {
16
+ ?>
17
+ <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-post-affiliate-pro.jpg" />
18
+ <div class="info">
19
+ <p>Integrate Paid Memberships Pro with the Post Affiliate Pro platform.</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="https://github.com/strangerstudios/pmpro-post-affiliate-pro/blob/master/readme.txt" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-post-affiliate-pro/pmpro-post-affiliate-pro.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-post-affiliate-pro/pmpro-post-affiliate-pro.php'), 'activate-plugin_pmpro-post-affiliate-pro/pmpro-post-affiliate-pro.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="http://www.paidmembershipspro.com/wp-content/uploads/plugins/pmpro-post-affiliate-pro.zip" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/pmpro-register-helper.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Register Helper
4
+ Slug: pmpro-register-helper
5
+ */
6
+ pmpro_add_addon('github', array(
7
+ 'title' => 'PMPro Register Helper',
8
+ 'version' => '.5.16.1',
9
+ 'widget' => 'pmpro_addon_pmpro_register_helper_widget',
10
+ 'enabled' => class_exists('PMProRH_Field')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_register_helper_widget($addon)
15
+ {
16
+ ?>
17
+ <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-register-helper.gif" />
18
+ <div class="info">
19
+ <p>Add additional meta fields to your PMPro checkout page and/or "Your Profile" pages. Support for text, select, multi-select, textarea, hidden, and custom HTML. Loop into existing checkout/profile field sections or add new ones.</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="https://github.com/strangerstudios/pmpro-register-helper/blob/master/readme.txt" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-register-helper/pmpro-register-helper.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-register-helper/pmpro-register-helper.php'), 'activate-plugin_pmpro-register-helper/pmpro-register-helper.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="http://www.paidmembershipspro.com/wp-content/uploads/plugins/pmpro-register-helper.zip" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/pmpro-require-code-to-register.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Require Code to Register
4
+ Slug: pmpro-require-code-to-register
5
+ */
6
+ pmpro_add_addon('gists', array(
7
+ 'title' => 'PMPro Require a Code to Register',
8
+ 'version' => '.1',
9
+ 'widget' => 'pmpro_addon_pmpro_require_code_to_register_widget',
10
+ 'enabled' => function_exists('my_pmpro_registration_checks_require_code_to_register')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_require_code_to_register_widget($addon)
15
+ {
16
+ ?>
17
+ <div class="info">
18
+ <p>Require a discount code to checkout for a specific level.</p>
19
+ <div class="actions">
20
+ <?php if($addon['enabled']) { ?>
21
+ <a target="_blank" href="https://gist.github.com/strangerstudios/5573829" class="button">Enabled</a>
22
+ <?php } else { ?>
23
+ <a target="_blank" href="https://gist.github.com/strangerstudios/5573829" class="button button-primary">View Gist</a>
24
+ <?php } ?>
25
+ </div>
26
+ </div> <!-- end info -->
27
+ <?php
28
+ }
adminpages/addons/pmpro-series.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Series
4
+ Slug: pmpro-series
5
+ */
6
+ pmpro_add_addon('github', array(
7
+ 'title' => 'PMPro Series',
8
+ 'version' => '.3',
9
+ 'widget' => 'pmpro_addon_pmpro_series_widget',
10
+ 'enabled' => class_exists("PMProSeries")
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_series_widget($addon)
15
+ {
16
+ ?>
17
+ <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-series.gif" />
18
+ <div class="info">
19
+ <p>"Drip feed" content to your members over the course of their membership. Serializes content by # of days post-registration.</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="<?php echo admin_url("edit.php?post_type=pmpro_series");?>" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-series/pmpro-series.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-series/pmpro-series.php'), 'activate-plugin_pmpro-series/pmpro-series.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="http://www.paidmembershipspro.com/wp-content/uploads/plugins/pmpro-series.zip" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/pmpro-shipping.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro Shipping Add On
4
+ Slug: pmpro-shipping
5
+ */
6
+ pmpro_add_addon('github', array(
7
+ 'title' => 'PMPro Shipping Add On',
8
+ 'version' => '.2.6',
9
+ 'widget' => 'pmpro_addon_pmpro_shipping_widget',
10
+ 'enabled' => function_exists('pmproship_pmpro_checkout_boxes')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_shipping_widget($addon)
15
+ {
16
+ ?>
17
+ <?php /* <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-shipping.jpg" /> */ ?>
18
+ <div class="info">
19
+ <p>Adds shipping fields to the checkout page, confirmation page, confirmation emails, member's list and edit user profile pages.</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="https://github.com/strangerstudios/pmpro-shipping/" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-shipping/pmpro-shipping.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-shipping/pmpro-shipping.php'), 'activate-plugin_pmpro-shipping/pmpro-shipping.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="http://www.paidmembershipspro.com/wp-content/uploads/plugins/pmpro-shipping.zip" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/pmpro-user-pages.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro User Pages
4
+ Slug: pmpro-user-pages
5
+ */
6
+ pmpro_add_addon('github', array(
7
+ 'title' => 'PMPro User Pages',
8
+ 'version' => '.3',
9
+ 'widget' => 'pmpro_addon_pmpro_user_pages_widget',
10
+ 'enabled' => function_exists('pmproup_pmpro_after_checkout')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_user_pages_widget($addon)
15
+ {
16
+ ?>
17
+ <div class="info">
18
+ <p>Creates a unique page for each Member after checkout, giving the Admin access to write customized content for each specific member.</p>
19
+ <div class="actions">
20
+ <?php if($addon['enabled']) { ?>
21
+ <a href="https://github.com/strangerstudios/pmpro-user-pages/blob/master/readme.txt" class="button">Enabled</a>
22
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-user-pages/pmpro-user-pages.php")) { ?>
23
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-user-pages/pmpro-user-pages.php'), 'activate-plugin_pmpro-user-pages/pmpro-user-pages.php')?>" class="button button-primary">Activate</a>
24
+ <?php } else { ?>
25
+ <a href="http://www.paidmembershipspro.com/wp-content/uploads/plugins/pmpro-user-pages.zip" class="button button-primary">Download</a>
26
+ <?php } ?>
27
+ </div>
28
+ </div> <!-- end info -->
29
+ <?php
30
+ }
adminpages/addons/pmpro-woocommerce.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro WooCommerce
4
+ Slug: pmpro-woocommerce
5
+ */
6
+ pmpro_add_addon('thirdparty', array(
7
+ 'title' => 'PMPro WooCommerce',
8
+ 'version' => '1.2.2',
9
+ 'widget' => 'pmpro_addon_pmpro_woocommerce_widget',
10
+ 'enabled' => function_exists('pmprowoo_add_membership_from_order')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_woocommerce_widget($addon)
15
+ {
16
+ ?>
17
+ <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-woocommerce.gif" />
18
+ <div class="info">
19
+ <p>Use WooCommerce to purchase membership or set members-only product pricing.</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="<?php echo admin_url("plugins.php");?>" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-woocommerce/pmpro-woocommerce.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-woocommerce/pmpro-woocommerce.php'), 'activate-plugin_pmpro-woocommerce/pmpro-woocommerce.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="<?php echo wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=pmpro-woocommerce'), 'install-plugin_pmpro-woocommerce'); ?>" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/pmpro-wp-affiliate.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: PMPro WP Affiliate Platform Integration
4
+ Slug: pmpro-wp-affiliate
5
+ */
6
+ pmpro_add_addon('thirdparty', array(
7
+ 'title' => 'PMPro WP Affiliate Platform Integration',
8
+ 'version' => '.3',
9
+ 'widget' => 'pmpro_addon_pmpro_wp_affiliate_widget',
10
+ 'enabled' => function_exists('wpa_pmpro_after_checkout')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_pmpro_wp_affiliate_widget($addon)
15
+ {
16
+ ?>
17
+ <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/pmpro-wp-affiliate-platform.jpg" />
18
+ <div class="info">
19
+ <p>Process an affiliate via WP Affiliate Platform after a PMPro checkout.</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="https://github.com/strangerstudios/pmpro-wp-affiliate-platform/" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../pmpro-wp-affiliate-platform/pmpro-wp-affiliate-platform.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=pmpro-wp-affiliate-platform/pmpro-wp-affiliate-platform.php'), 'activate-plugin_pmpro-wp-affiliate-platform/pmpro-wp-affiliate-platform.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="http://www.paidmembershipspro.com/wp-content/uploads/plugins/pmpro-wp-affiliate-platform.zip" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/addons/tml.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: Theme My Login
4
+ Slug: pmpro-tml
5
+ */
6
+ pmpro_add_addon('recommended', array(
7
+ 'title' => 'Theme My Login',
8
+ 'widget' => 'pmpro_addon_tml_widget',
9
+ 'enabled' => class_exists('Theme_My_Login'),
10
+ 'version' => '6.3.10'
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_tml_widget($addon)
15
+ {
16
+ ?>
17
+ <div class="info">
18
+ <p>This plugin themes the WordPress login, registration and forgot password pages according to your current theme. By <a href="http://www.jfarthing.com/" target="_blank">Jeff Farthing</a></p>
19
+ <div class="actions">
20
+ <form method="post" name="component-actions" action="">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="<?php echo admin_url("plugins.php");?>" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../theme-my-login/theme-my-login.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=theme-my-login/theme-my-login.php'), 'activate-plugin_theme-my-login/theme-my-login.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="<?php echo wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=theme-my-login'), 'install-plugin_theme-my-login'); ?>" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </form>
29
+ </div>
30
+ </div> <!-- end info -->
31
+ <?php
32
+ }
adminpages/addons/wp-bouncer.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Addon: WP Bouncer
4
+ Slug: wp-bouncer
5
+ */
6
+ pmpro_add_addon('repo', array(
7
+ 'title' => 'WP Bouncer',
8
+ 'version' => '1.1',
9
+ 'widget' => 'pmpro_addon_wp_bouncer_widget',
10
+ 'enabled' => class_exists('WP_Bouncer')
11
+ )
12
+ );
13
+
14
+ function pmpro_addon_wp_bouncer_widget($addon)
15
+ {
16
+ ?>
17
+ <img class="addon-thumb" src="<?php echo PMPRO_URL?>/adminpages/addons/images/wp-bouncer.gif" />
18
+ <div class="info">
19
+ <p>Make sure users are only logged in from one computer or device at a time.</p>
20
+ <div class="actions">
21
+ <?php if($addon['enabled']) { ?>
22
+ <a href="http://wordpress.org/plugins/wp-bouncer/" class="button">Enabled</a>
23
+ <?php } elseif(file_exists(dirname(__FILE__) . "/../../../wp-bouncer/wp-bouncer.php")) { ?>
24
+ <a href="<?php echo wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin=wp-bouncer/wp-bouncer.php'), 'activate-plugin_wp-bouncer/wp-bouncer.php')?>" class="button button-primary">Activate</a>
25
+ <?php } else { ?>
26
+ <a href="<?php echo wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=wp-bouncer'), 'install-plugin_wp-bouncer'); ?>" class="button button-primary">Download</a>
27
+ <?php } ?>
28
+ </div>
29
+ </div> <!-- end info -->
30
+ <?php
31
+ }
adminpages/admin_footer.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <div class="clear"></div>
2
+ </div>
adminpages/admin_header.php ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/functions.php");
3
+
4
+ if(isset($_REQUEST['page']))
5
+ $view = $_REQUEST['page'];
6
+ else
7
+ $view = "";
8
+
9
+ global $pmpro_ready, $msg, $msgt;
10
+ $pmpro_ready = pmpro_is_ready();
11
+ if(!$pmpro_ready)
12
+ {
13
+ global $pmpro_level_ready, $pmpro_gateway_ready, $pmpro_pages_ready;
14
+ if(!isset($edit))
15
+ {
16
+ if(isset($_REQUEST['edit']))
17
+ $edit = $_REQUEST['edit'];
18
+ else
19
+ $edit = false;
20
+ }
21
+
22
+ if(empty($msg))
23
+ $msg = -1;
24
+ if(empty($pmpro_level_ready) && empty($edit))
25
+ $msgt .= " <a href=\"?page=pmpro-membershiplevels&edit=-1\">" . __("Add a membership level to get started.", "pmpro") . "</a>";
26
+ elseif($pmpro_level_ready && !$pmpro_pages_ready && $view != "pmpro-pagesettings")
27
+ $msgt .= " <a href=\"?page=pmpro-pagesettings\">" . __("Setup the membership pages", "pmpro") . "</a>.";
28
+ elseif($pmpro_level_ready && $pmpro_pages_ready && !$pmpro_gateway_ready && $view != "pmpro-paymentsettings")
29
+ $msgt .= " <a href=\"?page=pmpro-paymentsettings\">" . __("Setup your SSL certificate and payment gateway", "pmpro") . "</a>.";
30
+
31
+ if(empty($msgt))
32
+ $msg = false;
33
+ }
34
+
35
+ if(!pmpro_checkLevelForStripeCompatibility())
36
+ {
37
+ $msg = -1;
38
+ $msgt = __("The billing details for some of your membership levels is not supported by Stripe.", "pmpro");
39
+ if($view == "pmpro-membershiplevels" && !empty($_REQUEST['edit']) && $_REQUEST['edit'] > 0)
40
+ {
41
+ if(!pmpro_checkLevelForStripeCompatibility($_REQUEST['edit']))
42
+ {
43
+ global $pmpro_stripe_error;
44
+ $pmpro_stripe_error = true;
45
+ $msg = -1;
46
+ $msgt = __("The billing details for this level are not supported by Stripe. Please review the notes in the Billing Details section below.", "pmpro");
47
+ }
48
+ }
49
+ elseif($view == "pmpro-membershiplevels")
50
+ $msgt .= " " . __("The levels with issues are highlighted below.", "pmpro");
51
+ else
52
+ $msgt .= " <a href=\"?page=pmpro-membershiplevels\">" . __("Please edit your levels", "pmpro") . "</a>.";
53
+ }
54
+
55
+ if(!pmpro_checkLevelForPayflowCompatibility())
56
+ {
57
+ $msg = -1;
58
+ $msgt = __("The billing details for some of your membership levels is not supported by Payflow.", "pmpro");
59
+ if($view == "pmpro-membershiplevels" && !empty($_REQUEST['edit']) && $_REQUEST['edit'] > 0)
60
+ {
61
+ if(!pmpro_checkLevelForPayflowCompatibility($_REQUEST['edit']))
62
+ {
63
+ global $pmpro_payflow_error;
64
+ $pmpro_payflow_error = true;
65
+ $msg = -1;
66
+ $msgt = __("The billing details for this level are not supported by Payflow. Please review the notes in the Billing Details section below.", "pmpro");
67
+ }
68
+ }
69
+ elseif($view == "pmpro-membershiplevels")
70
+ $msgt .= " " . __("The levels with issues are highlighted below.", "pmpro");
71
+ else
72
+ $msgt .= " <a href=\"?page=pmpro-membershiplevels\">" . __("Please edit your levels", "pmpro") . "</a>.";
73
+ }
74
+
75
+ if(!pmpro_checkLevelForBraintreeCompatibility())
76
+ {
77
+ $msg = -1;
78
+ $msgt = __("The billing details for some of your membership levels is not supported by Braintree.", "pmpro");
79
+ if($view == "pmpro-membershiplevels" && !empty($_REQUEST['edit']) && $_REQUEST['edit'] > 0)
80
+ {
81
+ if(!pmpro_checkLevelForBraintreeCompatibility($_REQUEST['edit']))
82
+ {
83
+ global $pmpro_braintree_error;
84
+ $pmpro_braintree_error = true;
85
+ $msg = -1;
86
+ $msgt = __("The billing details for this level are not supported by Braintree. Please review the notes in the Billing Details section below.", "pmpro");
87
+ }
88
+ }
89
+ elseif($view == "pmpro-membershiplevels")
90
+ $msgt .= " " . __("The levels with issues are highlighted below.", "pmpro");
91
+ else
92
+ $msgt .= " <a href=\"?page=pmpro-membershiplevels\">" . __("Please edit your levels", "pmpro") . "</a>.";
93
+ }
94
+
95
+ if(!pmpro_checkLevelForTwoCheckoutCompatibility())
96
+ {
97
+ $msg = -1;
98
+ $msgt = __("The billing details for some of your membership levels is not supported by TwoCheckout.", "pmpro");
99
+ if($view == "pmpro-membershiplevels" && !empty($_REQUEST['edit']) && $_REQUEST['edit'] > 0)
100
+ {
101
+ if(!pmpro_checkLevelForTwoCheckoutCompatibility($_REQUEST['edit']))
102
+ {
103
+ global $pmpro_twocheckout_error;
104
+ $pmpro_twocheckout_error = true;
105
+
106
+ $msg = -1;
107
+ $msgt = __("The billing details for this level are not supported by 2Checkout. Please review the notes in the Billing Details section below.", "pmpro");
108
+ }
109
+ }
110
+ elseif($view == "pmpro-membershiplevels")
111
+ $msgt .= " " . __("The levels with issues are highlighted below.", "pmpro");
112
+ else
113
+ $msgt .= " <a href=\"?page=pmpro-membershiplevels\">" . __("Please edit your levels", "pmpro") . "</a>.";
114
+ }
115
+
116
+ if(!empty($msg))
117
+ {
118
+ ?>
119
+ <div id="message" class="<?php if($msg > 0) echo "updated fade"; else echo "error"; ?>"><p><?php echo $msgt?></p></div>
120
+ <?php
121
+ }
122
+
123
+ ?>
124
+ <div class="wrap pmpro_admin">
125
+ <div class="pmpro_banner">
126
+ <a class="pmpro_logo" title="Paid Memberships Pro - Membership Plugin for WordPress" target="_blank" href="<?php echo pmpro_https_filter("http://www.paidmembershipspro.com")?>"><img src="<?php echo PMPRO_URL?>/images/Paid-Memberships-Pro.png" width="350" height="75" border="0" alt="Paid Memberships Pro(c) - All Rights Reserved" /></a>
127
+ <div class="pmpro_meta"><span class="pmpro_tag-grey">v<?php echo PMPRO_VERSION?></span><a target="_blank" class="pmpro_tag-blue" href="<?php echo pmpro_https_filter("http://www.paidmembershipspro.com")?>"><?php _e('Plugin Support', 'pmpro');?></a><a target="_blank" class="pmpro_tag-blue" href="http://www.paidmembershipspro.com/forums/"><?php _e('User Forum', 'pmpro');?></a></div>
128
+
129
+ <br style="clear:both;" />
130
+ </div>
131
+
132
+ <div id="pmpro_notifications">
133
+ </div>
134
+ <script>
135
+ jQuery(document).ready(function() {
136
+ jQuery.get('<?php echo get_admin_url(NULL, "/admin-ajax.php?action=pmpro_notifications"); ?>', function(data) {
137
+ if(data && data != 'NULL')
138
+ jQuery('#pmpro_notifications').html(data);
139
+ });
140
+ });
141
+ </script>
142
+
143
+ <?php
144
+ $settings_tabs = array("pmpro-membershiplevels", "pmpro-pagesettings", "pmpro-paymentsettings", "pmpro-emailsettings", "pmpro-advancedsettings", "pmpro-addons");
145
+ if(in_array($view, $settings_tabs))
146
+ {
147
+ ?>
148
+ <h3 class="nav-tab-wrapper">
149
+ <a href="admin.php?page=pmpro-membershiplevels" class="nav-tab<?php if($view == 'pmpro-membershiplevels') { ?> nav-tab-active<?php } ?>"><?php _e('Membership Levels', 'pmpro');?></a>
150
+ <a href="admin.php?page=pmpro-pagesettings" class="nav-tab<?php if($view == 'pmpro-pagesettings') { ?> nav-tab-active<?php } ?>"><?php _e('Pages', 'pmpro');?></a>
151
+ <a href="admin.php?page=pmpro-paymentsettings" class="nav-tab<?php if($view == 'pmpro-paymentsettings') { ?> nav-tab-active<?php } ?>"><?php _e('Payment Gateway &amp; SSL', 'pmpro');?></a>
152
+ <a href="admin.php?page=pmpro-emailsettings" class="nav-tab<?php if($view == 'pmpro-emailsettings') { ?> nav-tab-active<?php } ?>"><?php _e('Email', 'pmpro');?></a>
153
+ <a href="admin.php?page=pmpro-advancedsettings" class="nav-tab<?php if($view == 'pmpro-advancedsettings') { ?> nav-tab-active<?php } ?>"><?php _e('Advanced', 'pmpro');?></a>
154
+ <a href="admin.php?page=pmpro-addons" class="nav-tab<?php if($view == 'pmpro-addons') { ?> nav-tab-active<?php } ?>"><?php _e('Add Ons', 'pmpro');?></a>
155
+ </h3>
156
+ <?php } ?>
adminpages/advancedsettings.php ADDED
@@ -0,0 +1,374 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //only admins can get this
3
+ if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_advancedsettings")))
4
+ {
5
+ die(__("You do not have permissions to perform this action.", "pmpro"));
6
+ }
7
+
8
+ global $wpdb, $msg, $msgt;
9
+
10
+ //get/set settings
11
+ if(!empty($_REQUEST['savesettings']))
12
+ {
13
+ //other settings
14
+ pmpro_setOption("nonmembertext");
15
+ pmpro_setOption("notloggedintext");
16
+ pmpro_setOption("rsstext");
17
+ pmpro_setOption("filterqueries");
18
+ pmpro_setOption("showexcerpts");
19
+ pmpro_setOption("hideads");
20
+ pmpro_setOption("hideadslevels");
21
+ pmpro_setOption("redirecttosubscription");
22
+
23
+ //captcha
24
+ pmpro_setOption("recaptcha");
25
+ pmpro_setOption("recaptcha_publickey");
26
+ pmpro_setOption("recaptcha_privatekey");
27
+
28
+ //tos
29
+ pmpro_setOption("tospage");
30
+
31
+ //footer link
32
+ pmpro_setOption("hide_footer_link");
33
+
34
+ // custom settings (added with pmpro_custom_advanced_settings hook)
35
+ foreach($_REQUEST as $key => $value ) {
36
+ if (strpos($key, 'custom_') === 0) {
37
+ pmpro_setOption($key);
38
+ }
39
+ }
40
+
41
+ //assume success
42
+ $msg = true;
43
+ $msgt = __("Your advanced settings have been updated.", "pmpro");
44
+ }
45
+
46
+ $nonmembertext = pmpro_getOption("nonmembertext");
47
+ $notloggedintext = pmpro_getOption("notloggedintext");
48
+ $rsstext = pmpro_getOption("rsstext");
49
+ $hideads = pmpro_getOption("hideads");
50
+ $filterqueries = pmpro_getOption('filterqueries');
51
+ $showexcerpts = pmpro_getOption("showexcerpts");
52
+ $hideadslevels = pmpro_getOption("hideadslevels");
53
+
54
+ if(is_multisite())
55
+ $redirecttosubscription = pmpro_getOption("redirecttosubscription");
56
+
57
+ $recaptcha = pmpro_getOption("recaptcha");
58
+ $recaptcha_publickey = pmpro_getOption("recaptcha_publickey");
59
+ $recaptcha_privatekey = pmpro_getOption("recaptcha_privatekey");
60
+
61
+ $tospage = pmpro_getOption("tospage");
62
+
63
+ $hide_footer_link = pmpro_getOption("hide_footer_link");
64
+
65
+ //default settings
66
+ if(!$nonmembertext)
67
+ {
68
+ $nonmembertext = sprintf( __( 'This content is for !!levels!! members only. <a href="%s">Register here</a>.', 'pmpro' ), wp_login_url() . "?action=register" );
69
+ pmpro_setOption("nonmembertext", $nonmembertext);
70
+ }
71
+ if(!$notloggedintext)
72
+ {
73
+ $notloggedintext = sprintf( __( 'Please <a href="%s">login</a> to view this content. (<a href="%s">Register here</a>.)', 'pmpro' ), wp_login_url( get_permalink() ), wp_login_url() . "?action=register" );
74
+ pmpro_setOption("notloggedintext", $notloggedintext);
75
+ }
76
+ if(!$rsstext)
77
+ {
78
+ $rsstext = __( 'This content is for members only. Visit the site and log in/register to read.', 'pmpro' );
79
+ pmpro_setOption("rsstext", $rsstext);
80
+ }
81
+
82
+ $levels = $wpdb->get_results( "SELECT * FROM {$wpdb->pmpro_membership_levels}", OBJECT );
83
+
84
+ require_once(dirname(__FILE__) . "/admin_header.php");
85
+ ?>
86
+
87
+ <form action="" method="post" enctype="multipart/form-data">
88
+ <h2><?php _e('Advanced Settings', 'pmpro');?></h2>
89
+
90
+ <table class="form-table">
91
+ <tbody>
92
+ <tr>
93
+ <th scope="row" valign="top">
94
+ <label for="nonmembertext"><?php _e('Message for Logged-in Non-members', 'pmpro');?>:</label>
95
+ </th>
96
+ <td>
97
+ <textarea name="nonmembertext" rows="3" cols="80"><?php echo stripslashes($nonmembertext)?></textarea><br />
98
+ <small class="litegray"><?php _e('This message replaces the post content for non-members. Available variables', 'pmpro');?>: !!levels!!, !!referrer!!</small>
99
+ </td>
100
+ </tr>
101
+ <tr>
102
+ <th scope="row" valign="top">
103
+ <label for="notloggedintext"><?php _e('Message for Logged-out Users', 'pmpro');?>:</label>
104
+ </th>
105
+ <td>
106
+ <textarea name="notloggedintext" rows="3" cols="80"><?php echo stripslashes($notloggedintext)?></textarea><br />
107
+ <small class="litegray"><?php _e('This message replaces the post content for logged-out visitors.', 'pmpro');?></small>
108
+ </td>
109
+ </tr>
110
+ <tr>
111
+ <th scope="row" valign="top">
112
+ <label for="rsstext"><?php _e('Message for RSS Feed', 'pmpro');?>:</label>
113
+ </th>
114
+ <td>
115
+ <textarea name="rsstext" rows="3" cols="80"><?php echo stripslashes($rsstext)?></textarea><br />
116
+ <small class="litegray"><?php _e('This message replaces the post content in RSS feeds.', 'pmpro');?></small>
117
+ </td>
118
+ </tr>
119
+
120
+ <tr>
121
+ <th scope="row" valign="top">
122
+ <label for="filterqueries"><?php _e("Filter searches and archives?", 'pmpro');?></label>
123
+ </th>
124
+ <td>
125
+ <select id="filterqueries" name="filterqueries">
126
+ <option value="0" <?php if(!$filterqueries) { ?>selected="selected"<?php } ?>><?php _e('No - Non-members will see restricted posts/pages in searches and archives.', 'pmpro');?></option>
127
+ <option value="1" <?php if($filterqueries == 1) { ?>selected="selected"<?php } ?>><?php _e('Yes - Only members will see restricted posts/pages in searches and archives.', 'pmpro');?></option>
128
+ </select>
129
+ </td>
130
+ </tr>
131
+ <tr>
132
+ <th scope="row" valign="top">
133
+ <label for="showexcerpts"><?php _e('Show Excerpts to Non-Members?', 'pmpro');?></label>
134
+ </th>
135
+ <td>
136
+ <select id="showexcerpts" name="showexcerpts">
137
+ <option value="0" <?php if(!$showexcerpts) { ?>selected="selected"<?php } ?>><?php _e('No - Hide excerpts.', 'pmpro');?></option>
138
+ <option value="1" <?php if($showexcerpts == 1) { ?>selected="selected"<?php } ?>><?php _e('Yes - Show excerpts.', 'pmpro');?></option>
139
+ </select>
140
+ </td>
141
+ </tr>
142
+ <tr>
143
+ <th scope="row" valign="top">
144
+ <label for="hideads">Hide Ads From Members?</label>
145
+ </th>
146
+ <td>
147
+ <select id="hideads" name="hideads" onchange="pmpro_updateHideAdsTRs();">
148
+ <option value="0" <?php if(!$hideads) { ?>selected="selected"<?php } ?>><?php _e('No', 'pmpro');?></option>
149
+ <option value="1" <?php if($hideads == 1) { ?>selected="selected"<?php } ?>><?php _e('Hide Ads From All Members', 'pmpro');?></option>
150
+ <option value="2" <?php if($hideads == 2) { ?>selected="selected"<?php } ?>><?php _e('Hide Ads From Certain Members', 'pmpro');?></option>
151
+ </select>
152
+ </td>
153
+ </tr>
154
+ <tr id="hideads_explanation" <?php if($hideads < 2) { ?>style="display: none;"<?php } ?>>
155
+ <th scope="row" valign="top">&nbsp;</th>
156
+ <td>
157
+ <p class="top0em"><?php _e('Ads from the following plugins will be automatically turned off', 'pmpro');?>: <em>Easy Adsense</em>, ...</p>
158
+ <p><?php _e('To hide ads in your template code, use code like the following', 'pmpro');?>:</p>
159
+ <pre lang="PHP">
160
+ if(pmpro_displayAds())
161
+ {
162
+ //insert ad code here
163
+ }
164
+ </pre>
165
+ </td>
166
+ </tr>
167
+ <tr id="hideadslevels_tr" <?php if($hideads != 2) { ?>style="display: none;"<?php } ?>>
168
+ <th scope="row" valign="top">
169
+ <label for="hideadslevels"><?php _e('Choose Levels to Hide Ads From', 'pmpro');?>:</label>
170
+ </th>
171
+ <td>
172
+ <div class="checkbox_box" <?php if(count($levels) > 5) { ?>style="height: 100px; overflow: auto;"<?php } ?>>
173
+ <?php
174
+ $hideadslevels = pmpro_getOption("hideadslevels");
175
+ if(!is_array($hideadslevels))
176
+ $hideadslevels = explode(",", $hideadslevels);
177
+
178
+ $sqlQuery = "SELECT * FROM $wpdb->pmpro_membership_levels ";
179
+ $levels = $wpdb->get_results($sqlQuery, OBJECT);
180
+ foreach($levels as $level)
181
+ {
182
+ ?>
183
+ <div class="clickable"><input type="checkbox" id="hideadslevels_<?php echo $level->id?>" name="hideadslevels[]" value="<?php echo $level->id?>" <?php if(in_array($level->id, $hideadslevels)) { ?>checked="checked"<?php } ?>> <?php echo $level->name?></div>
184
+ <?php
185
+ }
186
+ ?>
187
+ </div>
188
+ <script>
189
+ jQuery('.checkbox_box input').click(function(event) {
190
+ event.stopPropagation()
191
+ });
192
+
193
+ jQuery('.checkbox_box div.clickable').click(function() {
194
+ var checkbox = jQuery(this).find(':checkbox');
195
+ checkbox.attr('checked', !checkbox.attr('checked'));
196
+ });
197
+ </script>
198
+ </td>
199
+ </tr>
200
+ <?php if(is_multisite()) { ?>
201
+ <tr>
202
+ <th scope="row" valign="top">
203
+ <label for="redirecttosubscription"><?php _e('Redirect all traffic from registration page to /susbcription/?', 'pmpro');?>: <em>(<?php _e('multisite only', 'pmpro');?>)</em></label>
204
+ </th>
205
+ <td>
206
+ <select id="redirecttosubscription" name="redirecttosubscription">
207
+ <option value="0" <?php if(!$redirecttosubscription) { ?>selected="selected"<?php } ?>><?php _e('No', 'pmpro');?></option>
208
+ <option value="1" <?php if($redirecttosubscription == 1) { ?>selected="selected"<?php } ?>><?php _e('Yes', 'pmpro');?></option>
209
+ </select>
210
+ </td>
211
+ </tr>
212
+ <?php } ?>
213
+ <tr>
214
+ <th scope="row" valign="top">
215
+ <label for="recaptcha"><?php _e('Use reCAPTCHA?', 'pmpro');?>:</label>
216
+ </th>
217
+ <td>
218
+ <select id="recaptcha" name="recaptcha" onchange="pmpro_updateRecaptchaTRs();">
219
+ <option value="0" <?php if(!$recaptcha) { ?>selected="selected"<?php } ?>><?php _e('No', 'pmpro');?></option>
220
+ <option value="1" <?php if($recaptcha == 1) { ?>selected="selected"<?php } ?>><?php _e('Yes - Free memberships only.', 'pmpro');?></option>
221
+ <option value="2" <?php if($recaptcha == 2) { ?>selected="selected"<?php } ?>><?php _e('Yes - All memberships.', 'pmpro');?></option>
222
+ </select><br />
223
+ <small><?php _e('A free reCAPTCHA key is required.', 'pmpro');?> <a href="https://www.google.com/recaptcha/admin/create"><?php _e('Click here to signup for reCAPTCHA', 'pmpro');?></a>.</small>
224
+ </td>
225
+ </tr>
226
+ <tr id="recaptcha_tr" <?php if(!$recaptcha) { ?>style="display: none;"<?php } ?>>
227
+ <th scope="row" valign="top">&nbsp;</th>
228
+ <td>
229
+ <label for="recaptcha_publickey"><?php _e('reCAPTCHA Public Key', 'pmpro');?>:</label>
230
+ <input type="text" name="recaptcha_publickey" size="60" value="<?php echo $recaptcha_publickey?>" />
231
+ <br /><br />
232
+ <label for="recaptcha_privatekey"><?php _e('reCAPTCHA Private Key', 'pmpro');?>:</label>
233
+ <input type="text" name="recaptcha_privatekey" size="60" value="<?php echo $recaptcha_privatekey?>" />
234
+ </td>
235
+ </tr>
236
+ <tr>
237
+ <th scope="row" valign="top">
238
+ <label for="tospage"><?php _e('Require Terms of Service on signups?', 'pmpro');?></label>
239
+ </th>
240
+ <td>
241
+ <?php
242
+ wp_dropdown_pages(array("name"=>"tospage", "show_option_none"=>"No", "selected"=>$tospage));
243
+ ?>
244
+ <br />
245
+ <small><?php _e('If yes, create a WordPress page containing your TOS agreement and assign it using the dropdown above.', 'pmpro');?></small>
246
+ </td>
247
+ </tr>
248
+
249
+ <?php /*
250
+ <tr>
251
+ <th scope="row" valign="top">
252
+ <label for="hide_footer_link">Hide the PMPro Link in the Footer?</label>
253
+ </th>
254
+ <td>
255
+ <select id="hide_footer_link" name="hide_footer_link">
256
+ <option value="0" <?php if(!$hide_footer_link) { ?>selected="selected"<?php } ?>>No - Leave the link. (Thanks!)</option>
257
+ <option value="1" <?php if($hide_footer_link == 1) { ?>selected="selected"<?php } ?>>Yes - Hide the link.</option>
258
+ </select>
259
+ </td>
260
+ </tr>
261
+ */
262
+
263
+ // Filter to Add More Advanced Settings for Misc Plugin Options, etc.
264
+ if (has_action('pmpro_custom_advanced_settings')) {
265
+ $custom_fields = apply_filters('pmpro_custom_advanced_settings', $custom_fields);
266
+ foreach ($custom_fields as $field) {
267
+ ?>
268
+ <tr>
269
+ <th valign="top" scope="row">
270
+ <label
271
+ for="<?php _e($field['field_name'], 'pmpro'); ?>"><?php _e($field['label'], 'pmpro'); ?></label>
272
+ </th>
273
+ <td>
274
+ <?php
275
+ switch ($field['field_type']) {
276
+ case 'select':
277
+ ?>
278
+ <select id="<?php _e($field['field_name'], 'pmpro'); ?>"
279
+ name="<?php _e($field['field_name'], 'pmpro'); ?>">
280
+ <?php foreach ($field['options'] as $option) {
281
+ ?>
282
+ <option value="<?php _e($option, 'pmpro'); ?>"
283
+ <?php
284
+ if ($option == pmpro_getOption($field['field_name'])) {
285
+ _e('selected', 'pmpro');
286
+ }
287
+ ?>
288
+ ><?php _e($option, 'pmpro'); ?></option>
289
+ <?php
290
+ } ?>
291
+ </select>
292
+ <?php
293
+ break;
294
+ case 'text':
295
+ ?>
296
+ <input id="<?php _e($field['field_name'], 'pmpro'); ?>"
297
+ name="<?php _e($field['field_name'], 'pmpro'); ?>"
298
+ type="<?php _e($field['field_type'], 'pmpro'); ?>"
299
+ value="<?php echo pmpro_getOption($field['field_name']); ?> ">
300
+ <?php
301
+ break;
302
+ case 'textarea':
303
+ ?>
304
+ <textarea id="<?php _e($field['field_name'], 'pmpro'); ?>"
305
+ name="<?php _e($field['field_name'], 'pmpro'); ?>">
306
+ <?php echo pmpro_getOption($field['field_name']); ?>
307
+ </textarea>
308
+ <?php
309
+ break;
310
+ default:
311
+ break;
312
+ }
313
+ if (!empty($field['description'])) {
314
+ ?>
315
+ <br>
316
+ <small><?php _e($field['description'], 'pmpro'); ?></small>
317
+ <?php
318
+ }
319
+ ?>
320
+ </td>
321
+ <?php
322
+ }
323
+ }
324
+ ?>
325
+ </tr>
326
+ </tbody>
327
+ </table>
328
+ <script>
329
+ function pmpro_updateHideAdsTRs()
330
+ {
331
+ var hideads = jQuery('#hideads').val();
332
+ if(hideads == 2)
333
+ {
334
+ jQuery('#hideadslevels_tr').show();
335
+ }
336
+ else
337
+ {
338
+ jQuery('#hideadslevels_tr').hide();
339
+ }
340
+
341
+ if(hideads > 0)
342
+ {
343
+ jQuery('#hideads_explanation').show();
344
+ }
345
+ else
346
+ {
347
+ jQuery('#hideads_explanation').hide();
348
+ }
349
+ }
350
+ pmpro_updateHideAdsTRs();
351
+
352
+ function pmpro_updateRecaptchaTRs()
353
+ {
354
+ var recaptcha = jQuery('#recaptcha').val();
355
+ if(recaptcha > 0)
356
+ {
357
+ jQuery('#recaptcha_tr').show();
358
+ }
359
+ else
360
+ {
361
+ jQuery('#recaptcha_tr').hide();
362
+ }
363
+ }
364
+ pmpro_updateRecaptchaTRs();
365
+ </script>
366
+
367
+ <p class="submit">
368
+ <input name="savesettings" type="submit" class="button button-primary" value="<?php _e('Save Settings', 'pmpro');?>" />
369
+ </p>
370
+ </form>
371
+
372
+ <?php
373
+ require_once(dirname(__FILE__) . "/admin_footer.php");
374
+ ?>
adminpages/dashboard.php ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Much of this code is borroed from yst_plugin_tools.php in the Yoast WordPress SEO plugin. Thanks, Yoast!
4
+ */
5
+
6
+ global $pmpro_feed;
7
+ $pmpro_feed = "http://feeds.feedburner.com/PaidMembershipsPro";
8
+
9
+ function pmpro_postbox($id, $title, $content)
10
+ {
11
+ ?>
12
+ <div id="<?php echo $id; ?>" class="postbox">
13
+ <div class="handlediv" title="Click to toggle"><br /></div>
14
+ <h3 class="hndle"><span><?php echo $title; ?></span></h3>
15
+ <div class="inside">
16
+ <?php echo $content; ?>
17
+ </div>
18
+ </div>
19
+ <?php
20
+ }
21
+
22
+ function pmpro_fetch_rss_items( $num )
23
+ {
24
+ global $pmpro_feed;
25
+
26
+ include_once(ABSPATH . WPINC . '/feed.php');
27
+ $rss = fetch_feed( $pmpro_feed );
28
+
29
+ // Bail if feed doesn't work
30
+ if ( is_wp_error($rss) )
31
+ return false;
32
+
33
+ $rss_items = $rss->get_items( 0, $rss->get_item_quantity( $num ) );
34
+
35
+ // If the feed was erroneously
36
+ if ( !$rss_items ) {
37
+ $md5 = md5( $pmpro_feed );
38
+ delete_transient( 'feed_' . $md5 );
39
+ delete_transient( 'feed_mod_' . $md5 );
40
+ $rss = fetch_feed( $pmpro_feed );
41
+ $rss_items = $rss->get_items( 0, $rss->get_item_quantity( $num ) );
42
+ }
43
+
44
+ return $rss_items;
45
+ }
46
+
47
+ /**
48
+ * Box with latest news from PaidMembershipsPro.com for sidebar
49
+ */
50
+ function pmpro_news()
51
+ {
52
+ $rss_items = pmpro_fetch_rss_items( 5 );
53
+
54
+ $content = '<ul>';
55
+ if ( !$rss_items ) {
56
+ $content .= '<li class="pmpro_news">no news items, feed might be broken...</li>';
57
+ } else {
58
+ foreach ( $rss_items as $item ) {
59
+ $content .= '<li class="pmpro_news">';
60
+ $content .= '<a class="rsswidget" href="'.esc_url( $item->get_permalink(), $protocolls=null, 'display' ).'">'. esc_html( $item->get_title() ) .'</a> ';
61
+ $content .= '</li>';
62
+ }
63
+ }
64
+ $content .= '</ul>';
65
+ $pmpro_postbox('pmprolatest', 'Recent Updates from PaidMembershipsPro.com', $content);
66
+ }
67
+
68
+ /**
69
+ * Widget with latest news from PaidMembershipsPro.com for dashbaord
70
+ */
71
+ function pmpro_db_widget()
72
+ {
73
+ global $pmpro_feed;
74
+
75
+ $options = get_option('pmpro_pmprodbwidget');
76
+
77
+ $network = '';
78
+ if ( function_exists('is_network_admin') && is_network_admin() )
79
+ $network = '_network';
80
+
81
+ if (isset($_POST['pmpro_removedbwidget'])) {
82
+ $options['removedbwidget'.$network] = true;
83
+ update_option('pmpro_pmprodbwidget',$options);
84
+ }
85
+ if ( isset($options['removedbwidget'.$network]) && $options['removedbwidget'.$network] ) {
86
+ echo "If you reload, this widget will be gone and never appear again, unless you decide to delete the database option 'pmpro_pmprodbwidget'.";
87
+ return;
88
+ }
89
+
90
+ $rss_items = pmpro_fetch_rss_items( 3 );
91
+
92
+ echo "<ul>";
93
+
94
+ if ( !$rss_items ) {
95
+ echo '<li class="pmpro_news">no news items, feed might be broken...</li>';
96
+ } else {
97
+ foreach ( $rss_items as $item ) {
98
+ echo '<li class="pmpro_news">';
99
+ echo '<a class="rsswidget" href="'.esc_url( $item->get_permalink(), $protocolls=null, 'display' ).'">'. esc_html( $item->get_title() ) .'</a>';
100
+ echo ' <span class="rss-date">'. $item->get_date(get_option('date_format')) .'</span>';
101
+ echo '<div class="rssSummary">'. esc_html( pmpro_text_limit( strip_tags( $item->get_description() ), 150 ) ).'</div>';
102
+ echo '</li>';
103
+ }
104
+ }
105
+
106
+ echo '</ul>';
107
+ echo '<br class="clear"/><div style="margin-top:10px;border-top: 1px solid #ddd; padding-top: 10px; text-align:center;">';
108
+ echo '<a target="_blank" href="'.$pmpro_feed.'"><img src="'.get_bloginfo('wpurl').'/wp-includes/images/rss.png" alt=""/> Subscribe with RSS</a>';
109
+ echo ' &nbsp; &nbsp; &nbsp; ';
110
+ echo '<a target="_blank" href="http://www.paidmembershipspro.com/blog/">View Online</a>';
111
+ echo '<form class="alignright" method="post"><input type="hidden" name="pmpro_removedbwidget" value="true"/><input title="Remove this widget from all users dashboards" class="button" type="submit" value="X"/></form>';
112
+ echo '</div>';
113
+ }
114
+
115
+ function pmpro_widget_setup()
116
+ {
117
+ $network = '';
118
+ if ( function_exists('is_network_admin') && is_network_admin() )
119
+ $network = '_network';
120
+
121
+ $options = get_option('pmpro_pmprodbwidget');
122
+ if ( !isset($options['removedbwidget'.$network]) || !$options['removedbwidget'.$network] )
123
+ wp_add_dashboard_widget( 'pmpro_db_widget' , 'The Latest From PaidMembershipsPro.com' , 'pmpro_db_widget');
124
+ }
125
+
126
+ add_action( 'wp_dashboard_setup', 'pmpro_widget_setup');
127
+ ?>
adminpages/discountcodes.php ADDED
@@ -0,0 +1,664 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //only admins can get this
3
+ if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_discountcodes")))
4
+ {
5
+ die(__("You do not have permissions to perform this action.", "pmpro"));
6
+ }
7
+
8
+ //vars
9
+ global $wpdb, $pmpro_currency_symbol;
10
+
11
+ if(isset($_REQUEST['edit']))
12
+ $edit = $_REQUEST['edit'];
13
+ else
14
+ $edit = false;
15
+
16
+ if(isset($_REQUEST['delete']))
17
+ $delete = $_REQUEST['delete'];
18
+ else
19
+ $delete = false;
20
+
21
+ if(isset($_REQUEST['saveid']))
22
+ $saveid = $_POST['saveid'];
23
+ else
24
+ $saveid = false;
25
+
26
+ if($saveid)
27
+ {
28
+ //get vars
29
+ $code = $_POST['code'];
30
+ $starts_month = $_POST['starts_month'];
31
+ $starts_day = $_POST['starts_day'];
32
+ $starts_year = $_POST['starts_year'];
33
+ $expires_month = $_POST['expires_month'];
34
+ $expires_day = $_POST['expires_day'];
35
+ $expires_year = $_POST['expires_year'];
36
+ $uses = $_POST['uses'];
37
+
38
+ //fix up dates
39
+ $starts = date("Y-m-d", strtotime($starts_month . "/" . $starts_day . "/" . $starts_year, current_time("timestamp")));
40
+ $expires = date("Y-m-d", strtotime($expires_month . "/" . $expires_day . "/" . $expires_year, current_time("timestamp")));
41
+
42
+ //updating or new?
43
+ if($saveid > 0)
44
+ {
45
+ $sqlQuery = "UPDATE $wpdb->pmpro_discount_codes SET code = '" . esc_sql($code) . "', starts = '" . $starts . "', expires = '" . $expires . "', uses = '" . intval($uses) . "' WHERE id = '" . $saveid . "' LIMIT 1";
46
+ if($wpdb->query($sqlQuery) !== false)
47
+ {
48
+ $pmpro_msg = __("Discount code updated successfully.", "pmpro");
49
+ $pmpro_msgt = "success";
50
+ $saved = true;
51
+ $edit = $saveid;
52
+ }
53
+ else
54
+ {
55
+ $pmpro_msg = __("Error updating discount code. That code may already be in use.", "pmpro");
56
+ $pmpro_msgt = "error";
57
+ }
58
+ }
59
+ else
60
+ {
61
+ $sqlQuery = "INSERT INTO $wpdb->pmpro_discount_codes (code, starts, expires, uses) VALUES('" . esc_sql($code) . "', '" . $starts . "', '" . $expires . "', '" . intval($uses) . "')";
62
+ if($wpdb->query($sqlQuery) !== false)
63
+ {
64
+ $pmpro_msg = __("Discount code added successfully.", "pmpro");
65
+ $pmpro_msgt = "success";
66
+ $saved = true;
67
+ $edit = $wpdb->insert_id;
68
+ }
69
+ else
70
+ {
71
+ $pmpro_msg = __("Error adding discount code. That code may already be in use.", "pmpro") . $wpdb->last_error;
72
+ $pmpro_msgt = "error";
73
+ }
74
+ }
75
+
76
+ //now add the membership level rows
77
+ if($saved && $edit > 0)
78
+ {
79
+ //get the submitted values
80
+ $all_levels_a = $_REQUEST['all_levels'];
81
+ if(!empty($_REQUEST['levels']))
82
+ $levels_a = $_REQUEST['levels'];
83
+ else
84
+ $levels_a = array();
85
+ $initial_payment_a = $_REQUEST['initial_payment'];
86
+ if(!empty($_REQUEST['recurring']))
87
+ $recurring_a = $_REQUEST['recurring'];
88
+ $billing_amount_a = $_REQUEST['billing_amount'];
89
+ $cycle_number_a = $_REQUEST['cycle_number'];
90
+ $cycle_period_a = $_REQUEST['cycle_period'];
91
+ $billing_limit_a = $_REQUEST['billing_limit'];
92
+ if(!empty($_REQUEST['custom_trial']))
93
+ $custom_trial_a = $_REQUEST['custom_trial'];
94
+ $trial_amount_a = $_REQUEST['trial_amount'];
95
+ $trial_limit_a = $_REQUEST['trial_limit'];
96
+ if(!empty($_REQUEST['expiration']))
97
+ $expiration_a = $_REQUEST['expiration'];
98
+ $expiration_number_a = $_REQUEST['expiration_number'];
99
+ $expiration_period_a = $_REQUEST['expiration_period'];
100
+
101
+ //clear the old rows
102
+ $sqlQuery = "DELETE FROM $wpdb->pmpro_discount_codes_levels WHERE code_id = '" . $edit . "'";
103
+ $wpdb->query($sqlQuery);
104
+
105
+ //add a row for each checked level
106
+ if(!empty($levels_a))
107
+ {
108
+ foreach($levels_a as $level_id)
109
+ {
110
+ //get the values ready
111
+ $n = array_search($level_id, $all_levels_a); //this is the key location of this level's values
112
+ $initial_payment = $initial_payment_a[$n];
113
+
114
+ //is this recurring?
115
+ if(!empty($recurring_a))
116
+ {
117
+ if(in_array($level_id, $recurring_a))
118
+ $recurring = 1;
119
+ else
120
+ $recurring = 0;
121
+ }
122
+ else
123
+ $recurring = 0;
124
+
125
+ if(!empty($recurring))
126
+ {
127
+ $billing_amount = $billing_amount_a[$n];
128
+ $cycle_number = $cycle_number_a[$n];
129
+ $cycle_period = $cycle_period_a[$n];
130
+ $billing_limit = $billing_limit_a[$n];
131
+
132
+ //custom trial
133
+ if(!empty($custom_trial_a))
134
+ {
135
+ if(in_array($level_id, $custom_trial_a))
136
+ $custom_trial = 1;
137
+ else
138
+ $custom_trial = 0;
139
+ }
140
+ else
141
+ $custom_trial = 0;
142
+
143
+ if(!empty($custom_trial))
144
+ {
145
+ $trial_amount = $trial_amount_a[$n];
146
+ $trial_limit = $trial_limit_a[$n];
147
+ }
148
+ else
149
+ {
150
+ $trial_amount = '';
151
+ $trial_limit = '';
152
+ }
153
+ }
154
+ else
155
+ {
156
+ $billing_amount = '';
157
+ $cycle_number = '';
158
+ $cycle_period = 'Month';
159
+ $billing_limit = '';
160
+ $custom_trial = 0;
161
+ $trial_amount = '';
162
+ $trial_limit = '';
163
+ }
164
+
165
+ if(!empty($expiration_a))
166
+ {
167
+ if(in_array($level_id, $expiration_a))
168
+ $expiration = 1;
169
+ else
170
+ $expiration = 0;
171
+ }
172
+ else
173
+ $expiration = 0;
174
+
175
+ if(!empty($expiration))
176
+ {
177
+ $expiration_number = $expiration_number_a[$n];
178
+ $expiration_period = $expiration_period_a[$n];
179
+ }
180
+ else
181
+ {
182
+ $expiration_number = '';
183
+ $expiration_period = 'Month';
184
+ }
185
+
186
+ //okay, do the insert
187
+ $sqlQuery = "INSERT INTO $wpdb->pmpro_discount_codes_levels (code_id, level_id, initial_payment, billing_amount, cycle_number, cycle_period, billing_limit, trial_amount, trial_limit, expiration_number, expiration_period) VALUES('" . esc_sql($edit) . "', '" . esc_sql($level_id) . "', '" . (double)esc_sql($initial_payment) . "', '" . (double)esc_sql($billing_amount) . "', '" . intval(esc_sql($cycle_number)) . "', '" . esc_sql($cycle_period) . "', '" . intval(esc_sql($billing_limit)) . "', '" . (double)esc_sql($trial_amount) . "', '" . intval(esc_sql($trial_limit)) . "', '" . intval(esc_sql($expiration_number)) . "', '" . esc_sql($expiration_period) . "')";
188
+
189
+ if($wpdb->query($sqlQuery) !== false)
190
+ {
191
+ //okay
192
+ do_action("pmpro_save_discount_code_level", $edit, $level_id);
193
+ }
194
+ else
195
+ {
196
+ $level_errors[] = sprintf(__("Error saving values for the %s level.", "pmpro"), $wpdb->get_var("SELECT name FROM $wpdb->pmpro_membership_levels WHERE id = '" . $level_id . "' LIMIT 1"));
197
+ }
198
+ }
199
+ }
200
+
201
+ //errors?
202
+ if(!empty($level_errors))
203
+ {
204
+ $pmpro_msg = __("There were errors updating the level values: ", "pmpro") . implode(" ", $level_errors);
205
+ $pmpro_msgt = "error";
206
+ }
207
+ else
208
+ {
209
+ //all good. set edit = NULL so we go back to the overview page
210
+ $edit = NULL;
211
+
212
+ do_action("pmpro_save_discount_code", $saveid);
213
+ }
214
+ }
215
+ }
216
+
217
+ //are we deleting?
218
+ if(!empty($delete))
219
+ {
220
+ //is this a code?
221
+ $code = $wpdb->get_var("SELECT code FROM $wpdb->pmpro_discount_codes WHERE id = '" . $delete . "' LIMIT 1");
222
+ if(!empty($code))
223
+ {
224
+ //action
225
+ do_action("pmpro_delete_discount_code", $delete);
226
+
227
+ //delete the code levels
228
+ $r1 = $wpdb->query("DELETE FROM $wpdb->pmpro_discount_codes_levels WHERE code_id = '" . $delete . "'");
229
+
230
+ if($r1 !== false)
231
+ {
232
+ //delete the code
233
+ $r2 = $wpdb->query("DELETE FROM $wpdb->pmpro_discount_codes WHERE id = '" . $delete . "' LIMIT 1");
234
+
235
+ if($r2 !== false)
236
+ {
237
+ $pmpro_msg = sprintf(__("Code %s deleted successfully.", "pmpro"), $code);
238
+ $pmpro_msgt = "success";
239
+ }
240
+ else
241
+ {
242
+ $pmpro_msg = __("Error deleting discount code. The code was only partially deleted. Please try again.", "pmpro");
243
+ $pmpro_msgt = "error";
244
+ }
245
+ }
246
+ else
247
+ {
248
+ $pmpro_msg = __("Error deleting code. Please try again.", "pmpro");
249
+ $pmpro_msgt = "error";
250
+ }
251
+ }
252
+ else
253
+ {
254
+ $pmpro_msg = __("Code not found.", "pmpro");
255
+ $pmpro_msgt = "error";
256
+ }
257
+ }
258
+
259
+ require_once(dirname(__FILE__) . "/admin_header.php");
260
+ ?>
261
+
262
+ <?php if($edit) { ?>
263
+
264
+ <h2>
265
+ <?php
266
+ if($edit > 0)
267
+ echo __("Edit Discount Code", "pmpro");
268
+ else
269
+ echo __("Add New Discount Code", "pmpro");
270
+ ?>
271
+ </h2>
272
+
273
+ <?php if(!empty($pmpro_msg)) { ?>
274
+ <div id="message" class="<?php if($pmpro_msgt == "success") echo "updated fade"; else echo "error"; ?>"><p><?php echo $pmpro_msg?></p></div>
275
+ <?php } ?>
276
+
277
+ <div>
278
+ <?php
279
+ // get the code...
280
+ if($edit > 0)
281
+ {
282
+ $code = $wpdb->get_row("SELECT *, UNIX_TIMESTAMP(starts) as starts, UNIX_TIMESTAMP(expires) as expires FROM $wpdb->pmpro_discount_codes WHERE id = '" . $edit . "' LIMIT 1", OBJECT);
283
+ $uses = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->pmpro_discount_codes_uses WHERE code_id = '" . $code->id . "'");
284
+ $levels = $wpdb->get_results("SELECT l.id, l.name, cl.initial_payment, cl.billing_amount, cl.cycle_number, cl.cycle_period, cl.billing_limit, cl.trial_amount, cl.trial_limit FROM $wpdb->pmpro_membership_levels l LEFT JOIN $wpdb->pmpro_discount_codes_levels cl ON l.id = cl.level_id WHERE cl.code_id = '" . $code->code . "'");
285
+ $temp_id = $code->id;
286
+ }
287
+ elseif(!empty($copy) && $copy > 0)
288
+ {
289
+ $code = $wpdb->get_row("SELECT *, UNIX_TIMESTAMP(starts) as starts, UNIX_TIMESTAMP(expires) as expires FROM $wpdb->pmpro_discount_codes WHERE id = '" . $copy . "' LIMIT 1", OBJECT);
290
+ $temp_id = $level->id;
291
+ $level->id = NULL;
292
+ }
293
+
294
+ // didn't find a discount code, let's add a new one...
295
+ if(empty($code->id)) $edit = -1;
296
+
297
+ //defaults for new codes
298
+ if($edit == -1)
299
+ {
300
+ $code = new stdClass();
301
+ $code->code = pmpro_getDiscountCode();
302
+ }
303
+ ?>
304
+ <form action="" method="post">
305
+ <input name="saveid" type="hidden" value="<?php echo $edit?>" />
306
+ <table class="form-table">
307
+ <tbody>
308
+ <tr>
309
+ <th scope="row" valign="top"><label><?php _e('ID', 'pmpro');?>:</label></th>
310
+ <td class="pmpro_lite"><?php if(!empty($code->id)) echo $code->id; else echo __("This will be generated when you save.", "pmpro");?></td>
311
+ </tr>
312
+
313
+ <tr>
314
+ <th scope="row" valign="top"><label for="code"><?php _e('Code', 'pmpro');?>:</label></th>
315
+ <td><input name="code" type="text" size="20" value="<?php echo str_replace("\"", "&quot;", stripslashes($code->code))?>" /></td>
316
+ </tr>
317
+
318
+ <?php
319
+ //some vars for the dates
320
+ $current_day = date("j");
321
+ if(!empty($code->starts))
322
+ $selected_starts_day = date("j", $code->starts);
323
+ else
324
+ $selected_starts_day = $current_day;
325
+ if(!empty($code->expires))
326
+ $selected_expires_day = date("j", $code->expires);
327
+ else
328
+ $selected_expires_day = $current_day;
329
+
330
+ $current_month = date("M");
331
+ if(!empty($code->starts))
332
+ $selected_starts_month = date("m", $code->starts);
333
+ else
334
+ $selected_starts_month = date("m");
335
+ if(!empty($code->expires))
336
+ $selected_expires_month = date("m", $code->expires);
337
+ else
338
+ $selected_expires_month = date("m");
339
+
340
+ $current_year = date("Y");
341
+ if(!empty($code->starts))
342
+ $selected_starts_year = date("Y", $code->starts);
343
+ else
344
+ $selected_starts_year = $current_year;
345
+ if(!empty($code->expires))
346
+ $selected_expires_year = date("Y", $code->expires);
347
+ else
348
+ $selected_expires_year = (int)$current_year + 1;
349
+ ?>
350
+
351
+ <tr>
352
+ <th scope="row" valign="top"><label for="starts"><?php _e('Start Date', 'pmpro');?>:</label></th>
353
+ <td>
354
+ <select name="starts_month">
355
+ <?php
356
+ for($i = 1; $i < 13; $i++)
357
+ {
358
+ ?>
359
+ <option value="<?php echo $i?>" <?php if($i == $selected_starts_month) { ?>selected="selected"<?php } ?>><?php echo date("M", strtotime($i . "/1/" . $current_year, current_time("timestamp")))?></option>
360
+ <?php
361
+ }
362
+ ?>
363
+ </select>
364
+ <input name="starts_day" type="text" size="2" value="<?php echo $selected_starts_day?>" />
365
+ <input name="starts_year" type="text" size="4" value="<?php echo $selected_starts_year?>" />
366
+ </td>
367
+ </tr>
368
+
369
+ <tr>
370
+ <th scope="row" valign="top"><label for="expires"><?php _e('Expiration Date', 'pmpro');?>:</label></th>
371
+ <td>
372
+ <select name="expires_month">
373
+ <?php
374
+ for($i = 1; $i < 13; $i++)
375
+ {
376
+ ?>
377
+ <option value="<?php echo $i?>" <?php if($i == $selected_expires_month) { ?>selected="selected"<?php } ?>><?php echo date("M", strtotime($i . "/1/" . $current_year, current_time("timestamp")))?></option>
378
+ <?php
379
+ }
380
+ ?>
381
+ </select>
382
+ <input name="expires_day" type="text" size="2" value="<?php echo $selected_expires_day?>" />
383
+ <input name="expires_year" type="text" size="4" value="<?php echo $selected_expires_year?>" />
384
+ </td>
385
+ </tr>
386
+
387
+ <tr>
388
+ <th scope="row" valign="top"><label for="uses"><?php _e('Uses', 'pmpro');?>:</label></th>
389
+ <td>
390
+ <input name="uses" type="text" size="10" value="<?php if(!empty($code->uses)) echo str_replace("\"", "&quot;", stripslashes($code->uses));?>" />
391
+ <small class="pmpro_lite"><?php _e('Leave blank for unlimited uses.', 'pmpro');?></small>
392
+ </td>
393
+ </tr>
394
+
395
+ </tbody>
396
+ </table>
397
+
398
+ <?php do_action("pmpro_discount_code_after_settings"); ?>
399
+
400
+ <h3><?php _e('Which Levels Will This Code Apply To?', 'pmpro'); ?></h3>
401
+
402
+ <div class="pmpro_discount_levels">
403
+ <?php
404
+ $levels = $wpdb->get_results("SELECT * FROM $wpdb->pmpro_membership_levels");
405
+ foreach($levels as $level)
406
+ {
407
+ //if this level is already managed for this discount code, use the code values
408
+ if($edit > 0)
409
+ {
410
+ $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 = '" . $edit . "' AND cl.level_id = '" . $level->id . "' LIMIT 1");
411
+ if($code_level)
412
+ {
413
+ $level = $code_level;
414
+ $level->checked = true;
415
+ }
416
+ else
417
+ $level_checked = false;
418
+ }
419
+ else
420
+ $level_checked = false;
421
+ ?>
422
+ <div>
423
+ <input type="hidden" name="all_levels[]" value="<?php echo $level->id?>" />
424
+ <input type="checkbox" name="levels[]" value="<?php echo $level->id?>" <?php if(!empty($level->checked)) { ?>checked="checked"<?php } ?> onclick="if(jQuery(this).is(':checked')) jQuery(this).next().show(); else jQuery(this).next().hide();" />
425
+ <?php echo $level->name?>
426
+ <div class="pmpro_discount_levels_pricing level_<?php echo $level->id?>" <?php if(empty($level->checked)) { ?>style="display: none;"<?php } ?>>
427
+ <table class="form-table">
428
+ <tbody>
429
+ <tr>
430
+ <th scope="row" valign="top"><label for="initial_payment"><?php _e('Initial Payment', 'pmpro');?>:</label></th>
431
+ <td>
432
+ <?php
433
+ if(pmpro_getCurrencyPosition() == "left")
434
+ echo $pmpro_currency_symbol;
435
+ ?>
436
+ <input name="initial_payment[]" type="text" size="20" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->initial_payment))?>" />
437
+ <?php
438
+ if(pmpro_getCurrencyPosition() == "right")
439
+ echo $pmpro_currency_symbol;
440
+ ?>
441
+ <small><?php _e('The initial amount collected at registration.', 'pmpro');?></small>
442
+ </td>
443
+ </tr>
444
+
445
+ <tr>
446
+ <th scope="row" valign="top"><label><?php _e('Recurring Subscription', 'pmpro');?>:</label></th>
447
+ <td><input class="recurring_checkbox" name="recurring[]" type="checkbox" value="<?php echo $level->id?>" <?php if(pmpro_isLevelRecurring($level)) { echo "checked='checked'"; } ?> onclick="if(jQuery(this).attr('checked')) { jQuery(this).parent().parent().siblings('.recurring_info').show(); if(!jQuery('#custom_trial_<?php echo $level->id?>').is(':checked')) jQuery(this).parent().parent().siblings('.trial_info').hide();} else jQuery(this).parent().parent().siblings('.recurring_info').hide();" /> <small><?php _e('Check if this level has a recurring subscription payment.', 'pmpro');?></small></td>
448
+ </tr>
449
+
450
+ <tr class="recurring_info" <?php if(!pmpro_isLevelRecurring($level)) {?>style="display: none;"<?php } ?>>
451
+ <th scope="row" valign="top"><label for="billing_amount"><?php _e('Billing Amount', 'pmpro');?>:</label></th>
452
+ <td>
453
+ <?php
454
+ if(pmpro_getCurrencyPosition() == "left")
455
+ echo $pmpro_currency_symbol;
456
+ ?>
457
+ <input name="billing_amount[]" type="text" size="20" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->billing_amount))?>" />
458
+ <?php
459
+ if(pmpro_getCurrencyPosition() == "right")
460
+ echo $pmpro_currency_symbol;
461
+ ?>
462
+ <small>per</small>
463
+ <input name="cycle_number[]" type="text" size="10" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->cycle_number))?>" />
464
+ <select name="cycle_period[]" onchange="updateCyclePeriod();">
465
+ <?php
466
+ $cycles = array( __('Day(s)', 'pmpro') => 'Day', __('Week(s)', 'pmpro') => 'Week', __('Month(s)', 'pmpro') => 'Month', __('Year(s)', 'pmpro') => 'Year' );
467
+ foreach ( $cycles as $name => $value ) {
468
+ echo "<option value='$value'";
469
+ if ( $level->cycle_period == $value ) echo " selected='selected'";
470
+ echo ">$name</option>";
471
+ }
472
+ ?>
473
+ </select>
474
+ <br /><small><?php _e('The amount to be billed one cycle after the initial payment.', 'pmpro');?></small>
475
+ </td>
476
+ </tr>
477
+
478
+ <tr class="recurring_info" <?php if(!pmpro_isLevelRecurring($level)) {?>style="display: none;"<?php } ?>>
479
+ <th scope="row" valign="top"><label for="billing_limit"><?php _e('Billing Cycle Limit', 'pmpro');?>:</label></th>
480
+ <td>
481
+ <input name="billing_limit[]" type="text" size="20" value="<?php echo $level->billing_limit?>" />
482
+ <br /><small><?php _e('The <strong>total</strong> number of recurring billing cycles for this level, including the trial period (if applicable) but not including the initial payment. Set to zero if membership is indefinite.', 'pmpro');?></small>
483
+ </td>
484
+ </tr>
485
+
486
+ <tr class="recurring_info" <?php if (!pmpro_isLevelRecurring($level)) echo "style='display:none;'";?>>
487
+ <th scope="row" valign="top"><label><?php _e('Custom Trial', 'pmpro');?>:</label></th>
488
+ <td><input id="custom_trial_<?php echo $level->id?>" name="custom_trial[]" type="checkbox" value="<?php echo $level->id?>" <?php if ( pmpro_isLevelTrial($level) ) { echo "checked='checked'"; } ?> onclick="if(jQuery(this).attr('checked')) jQuery(this).parent().parent().siblings('.trial_info').show(); else jQuery(this).parent().parent().siblings('.trial_info').hide();" /> <?php _e('Check to add a custom trial period.', 'pmpro');?></td>
489
+ </tr>
490
+
491
+ <tr class="trial_info recurring_info" <?php if (!pmpro_isLevelTrial($level)) echo "style='display:none;'";?>>
492
+ <th scope="row" valign="top"><label for="trial_amount"><?php _e('Trial Billing Amount', 'pmpro');?>:</label></th>
493
+ <td>
494
+ <?php
495
+ if(pmpro_getCurrencyPosition() == "left")
496
+ echo $pmpro_currency_symbol;
497
+ ?>
498
+ <input name="trial_amount[]" type="text" size="20" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->trial_amount))?>" />
499
+ <?php
500
+ if(pmpro_getCurrencyPosition() == "right")
501
+ echo $pmpro_currency_symbol;
502
+ ?>
503
+ <small><?php _e('for the first', 'pmpro');?></small>
504
+ <input name="trial_limit[]" type="text" size="10" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->trial_limit))?>" />
505
+ <small><?php _e('subscription payments', 'pmpro');?>.</small>
506
+ </td>
507
+ </tr>
508
+
509
+ <tr>
510
+ <th scope="row" valign="top"><label><?php _e('Membership Expiration', 'pmpro');?>:</label></th>
511
+ <td><input id="expiration" name="expiration[]" type="checkbox" value="<?php echo $level->id?>" <?php if(pmpro_isLevelExpiring($level)) { echo "checked='checked'"; } ?> onclick="if(jQuery(this).is(':checked')) { jQuery(this).parent().parent().siblings('.expiration_info').show(); } else { jQuery(this).parent().parent().siblings('.expiration_info').hide();}" /> <?php _e('Check this to set when membership access expires.', 'pmpro');?></td>
512
+ </tr>
513
+
514
+ <tr class="expiration_info" <?php if(!pmpro_isLevelExpiring($level)) {?>style="display: none;"<?php } ?>>
515
+ <th scope="row" valign="top"><label for="billing_amount"><?php _e('Expires In', 'pmpro');?>:</label></th>
516
+ <td>
517
+ <input id="expiration_number" name="expiration_number[]" type="text" size="10" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->expiration_number))?>" />
518
+ <select id="expiration_period" name="expiration_period[]">
519
+ <?php
520
+ $cycles = array( __('Day(s)', 'pmpro') => 'Day', __('Week(s)', 'pmpro') => 'Week', __('Month(s)', 'pmpro') => 'Month', __('Year(s)', 'pmpro') => 'Year' );
521
+ foreach ( $cycles as $name => $value ) {
522
+ echo "<option value='$value'";
523
+ if ( $level->expiration_period == $value ) echo " selected='selected'";
524
+ echo ">$name</option>";
525
+ }
526
+ ?>
527
+ </select>
528
+ <br /><small><?php _e('Set the duration of membership access. Note that the any future payments (recurring subscription, if any) will be cancelled when the membership expires.', 'pmpro');?></small>
529
+ </td>
530
+ </tr>
531
+ </tbody>
532
+ </table>
533
+
534
+ <?php do_action("pmpro_discount_code_after_level_settings", $edit, $level); ?>
535
+
536
+ </div>
537
+ </div>
538
+ <script>
539
+
540
+ </script>
541
+ <?php
542
+ }
543
+ ?>
544
+ </div>
545
+
546
+ <p class="submit topborder">
547
+ <input name="save" type="submit" class="button button-primary" value="Save Code" />
548
+ <input name="cancel" type="button" class="button button-secondary" value="Cancel" onclick="location.href='<?php echo get_admin_url(NULL, '/admin.php?page=pmpro-discountcodes')?>';" />
549
+ </p>
550
+ </form>
551
+ </div>
552
+
553
+ <?php } else { ?>
554
+
555
+ <h2>
556
+ <?php _e('Memberships Discount Codes', 'pmpro');?>
557
+ <a href="admin.php?page=pmpro-discountcodes&edit=-1" class="add-new-h2"><?php _e('Add New Discount Code', 'pmpro');?></a>
558
+ </h2>
559
+
560
+ <?php if(!empty($pmpro_msg)) { ?>
561
+ <div id="message" class="<?php if($pmpro_msgt == "success") echo "updated fade"; else echo "error"; ?>"><p><?php echo $pmpro_msg?></p></div>
562
+ <?php } ?>
563
+
564
+ <form id="posts-filter" method="get" action="">
565
+ <p class="search-box">
566
+ <label class="screen-reader-text" for="post-search-input"><?php _e('Search Discount Codes', 'pmpro');?>:</label>
567
+ <input type="hidden" name="page" value="pmpro-discountcodes" />
568
+ <input id="post-search-input" type="text" value="<?php if(!empty($s)) echo $s;?>" name="s" size="30" />
569
+ <input class="button" type="submit" value="<?php _e('Search', 'pmpro');?>" id="search-submit "/>
570
+ </p>
571
+ </form>
572
+
573
+ <br class="clear" />
574
+ <?php
575
+ $sqlQuery = "SELECT *, UNIX_TIMESTAMP(starts) as starts, UNIX_TIMESTAMP(expires) as expires FROM $wpdb->pmpro_discount_codes ";
576
+ if(!empty($s))
577
+ $sqlQuery .= "WHERE code LIKE '%$s%' ";
578
+ $sqlQuery .= "ORDER BY id ASC";
579
+
580
+ $codes = $wpdb->get_results($sqlQuery, OBJECT);
581
+ ?>
582
+ <table class="widefat">
583
+ <thead>
584
+ <tr>
585
+ <th><?php _e('ID', 'pmpro');?></th>
586
+ <th><?php _e('Code', 'pmpro');?></th>
587
+ <th><?php _e('Starts', 'pmpro');?></th>
588
+ <th><?php _e('Expires', 'pmpro');?></th>
589
+ <th><?php _e('Uses', 'pmpro');?></th>
590
+ <th><?php _e('Levels', 'pmpro');?></th>
591
+ <?php do_action("pmpro_discountcodes_extra_cols_header", $codes);?>
592
+ <th></th>
593
+ <th></th>
594
+ </tr>
595
+ </thead>
596
+ <tbody>
597
+ <?php
598
+ if(!$codes)
599
+ {
600
+ ?>
601
+ <tr><td colspan="7" class="pmpro_pad20">
602
+ <p><?php _e('Discount codes allow you to offer your memberships at discounted prices to select customers.', 'pmpro');?> <a href="admin.php?page=pmpro-discountcodes&edit=-1"><?php _e('Create your first discount code now', 'pmpro');?></a>.</p>
603
+ </td></tr>
604
+ <?php
605
+ }
606
+ else
607
+ {
608
+ foreach($codes as $code)
609
+ {
610
+ ?>
611
+ <tr>
612
+ <td><?php echo $code->id?></td>
613
+ <td>
614
+ <a href="?page=pmpro-discountcodes&edit=<?php echo $code->id?>"><?php echo $code->code?></a>
615
+ </td>
616
+ <td>
617
+ <?php echo date(get_option('date_format'), $code->starts)?>
618
+ </td>
619
+ <td>
620
+ <?php echo date(get_option('date_format'), $code->expires)?>
621
+ </td>
622
+ <td>
623
+ <?php
624
+ $uses = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->pmpro_discount_codes_uses WHERE code_id = '" . $code->id . "'");
625
+ if($code->uses > 0)
626
+ echo "<strong>" . (int)$uses . "</strong>/" . $code->uses;
627
+ else
628
+ echo "<strong>" . (int)$uses . "</strong>/unlimited";
629
+ ?>
630
+ </td>
631
+ <td>
632
+ <?php
633
+ $sqlQuery = "SELECT l.id, l.name FROM $wpdb->pmpro_membership_levels l LEFT JOIN $wpdb->pmpro_discount_codes_levels cl ON l.id = cl.level_id WHERE cl.code_id = '" . $code->id . "'";
634
+ $levels = $wpdb->get_results($sqlQuery);
635
+
636
+ $level_names = array();
637
+ foreach($levels as $level)
638
+ $level_names[] = "<a target=\"_blank\" href=\"" . pmpro_url("checkout", "?level=" . $level->id . "&discount_code=" . $code->code) . "\">" . $level->name . "</a>";
639
+ if($level_names)
640
+ echo implode(", ", $level_names);
641
+ else
642
+ echo "None";
643
+ ?>
644
+ </td>
645
+ <?php do_action("pmpro_discountcodes_extra_cols_body", $code);?>
646
+ <td>
647
+ <a href="?page=pmpro-discountcodes&edit=<?php echo $code->id?>"><?php _e('edit', 'pmpro');?></a>
648
+ </td>
649
+ <td>
650
+ <a href="javascript:askfirst('<?php printf(__('Are you sure you want to delete the %s discount code? The subscriptions for existing users will not change, but new users will not be able to use this code anymore.', 'pmpro'), $code->code);?>', '?page=pmpro-discountcodes&delete=<?php echo $code->id?>'); void(0);"><?php _e('delete', 'pmpro');?></a>
651
+ </td>
652
+ </tr>
653
+ <?php
654
+ }
655
+ }
656
+ ?>
657
+ </tbody>
658
+ </table>
659
+
660
+ <?php } ?>
661
+
662
+ <?php
663
+ require_once(dirname(__FILE__) . "/admin_footer.php");
664
+ ?>
adminpages/emailsettings.php ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //only admins can get this
3
+ if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_emailsettings")))
4
+ {
5
+ die(__("You do not have permissions to perform this action.", "pmpro"));
6
+ }
7
+
8
+ global $wpdb, $msg, $msgt;
9
+
10
+ //get/set settings
11
+ global $pmpro_pages;
12
+ if(!empty($_REQUEST['savesettings']))
13
+ {
14
+ //email options
15
+ pmpro_setOption("from_email");
16
+ pmpro_setOption("from_name");
17
+ pmpro_setOption("only_filter_pmpro_emails");
18
+
19
+ pmpro_setOption("email_admin_checkout");
20
+ pmpro_setOption("email_admin_changes");
21
+ pmpro_setOption("email_admin_cancels");
22
+ pmpro_setOption("email_admin_billing");
23
+
24
+ pmpro_setOption("email_member_notification");
25
+
26
+ //assume success
27
+ $msg = true;
28
+ $msgt = "Your email settings have been updated.";
29
+ }
30
+
31
+ $from_email = pmpro_getOption("from_email");
32
+ $from_name = pmpro_getOption("from_name");
33
+ $only_filter_pmpro_emails = pmpro_getOption("only_filter_pmpro_emails");
34
+
35
+ $email_admin_checkout = pmpro_getOption("email_admin_checkout");
36
+ $email_admin_changes = pmpro_getOption("email_admin_changes");
37
+ $email_admin_cancels = pmpro_getOption("email_admin_cancels");
38
+ $email_admin_billing = pmpro_getOption("email_admin_billing");
39
+
40
+ $email_member_notification = pmpro_getOption("email_member_notification");
41
+
42
+ if(empty($from_email))
43
+ {
44
+ $parsed = parse_url(home_url());
45
+ $hostname = $parsed[host];
46
+ $hostparts = split("\.", $hostname);
47
+ $email_domain = $hostparts[count($hostparts) - 2] . "." . $hostparts[count($hostparts) - 1];
48
+ $from_email = "wordpress@" . $email_domain;
49
+ pmpro_setOption("from_email", $from_email);
50
+ }
51
+
52
+ if(empty($from_name))
53
+ {
54
+ $from_name = "WordPress";
55
+ pmpro_setOption("from_name", $from_name);
56
+ }
57
+
58
+ // default from email wordpress@sitename
59
+ $sitename = strtolower( $_SERVER['SERVER_NAME'] );
60
+ if ( substr( $sitename, 0, 4 ) == 'www.' ) {
61
+ $sitename = substr( $sitename, 4 );
62
+ }
63
+ $default_from_email = 'wordpress@' . $sitename;
64
+
65
+ require_once(dirname(__FILE__) . "/admin_header.php");
66
+ ?>
67
+
68
+ <form action="" method="post" enctype="multipart/form-data">
69
+ <h2><?php _e('Email Settings', 'pmpro');?></h2>
70
+ <p><?php _e('By default, system generated emails are sent from <em><strong>wordpress@yourdomain.com</strong></em>. You can update this from address using the fields below.', 'pmpro');?></p>
71
+
72
+ <p><?php _e('To modify the appearance of system generated emails, add the files <em>email_header.html</em> and <em>email_footer.html</em> to your theme\'s directory. This will modify both the WordPress default messages as well as messages generated by Paid Memberships Pro. <a title="Paid Memberships Pro - Member Communications" target="_blank" href="http://www.paidmembershipspro.com/documentation/member-communications/">Click here to learn more about Paid Memberships Pro emails</a>.', 'pmpro');?></p>
73
+
74
+ <table class="form-table">
75
+ <tbody>
76
+ <tr>
77
+ <th scope="row" valign="top">
78
+ <label for="from_email"><?php _e('From Email', 'pmpro');?>:</label>
79
+ </th>
80
+ <td>
81
+ <input type="text" name="from_email" size="60" value="<?php echo $from_email?>" />
82
+ </td>
83
+ </tr>
84
+ <tr>
85
+ <th scope="row" valign="top">
86
+ <label for="from_name"><?php _e('From Name', 'pmpro');?>:</label>
87
+ </th>
88
+ <td>
89
+ <input type="text" name="from_name" size="60" value="<?php echo $from_name?>" />
90
+ </td>
91
+ </tr>
92
+ <tr>
93
+ <th scope="row" valign="top">
94
+ <label for="only_filter_pmpro_emails"><?php _e('Only Filter PMPro Emails?', 'pmpro');?>:</label>
95
+ </th>
96
+ <td>
97
+ <input type="checkbox" id="only_filter_pmpro_emails" name="only_filter_pmpro_emails" value="1" <?php if(!empty($only_filter_pmpro_emails)) { ?>checked="checked"<?php } ?> />
98
+ <?php _e('If unchecked, all emails from "WordPress &lt;' . $default_from_email . '&gt;" will be filtered to use the above settings.', 'pmpro');?>
99
+ </td>
100
+ </tr>
101
+ </tbody>
102
+ </table>
103
+
104
+ <?php /* going to put something like this here in next version
105
+ <h3><?php _e('Modify System-generated Email Templates', 'pmpro');?>:</h3>
106
+ <?php
107
+ if (function_exists('pmproet_scripts'))
108
+ {
109
+ _e('You have installed the PMPro Email Templates add on. <a href="' . admin_url('admin.php?page=pmpro-email-templates') . '">Click here to modify email templates</a>');
110
+ }
111
+ ?>
112
+ <p><?php _e('To modify the subject line and body content of system generated emails, <a title="Paid Memberships Pro - Email Templates Plugin" target="_blank" href="' . wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=pmpro-email-templates-addon'), 'install-plugin_pmpro-email-templates-addon') . '">Install and Activate the PMPro Email Templates add on</a>.', 'pmpro'); ?></p>
113
+ */ ?>
114
+
115
+ <h3><?php _e('Send the site admin emails', 'pmpro');?>:</h3>
116
+
117
+ <table class="form-table">
118
+ <tbody>
119
+ <tr>
120
+ <th scope="row" valign="top">
121
+ <label for="email_admin_checkout"><?php _e('Checkout', 'pmpro');?>:</label>
122
+ </th>
123
+ <td>
124
+ <input type="checkbox" id="email_admin_checkout" name="email_admin_checkout" value="1" <?php if(!empty($email_admin_checkout)) { ?>checked="checked"<?php } ?> />
125
+ <?php _e('when a member checks out.', 'pmpro');?>
126
+ </td>
127
+ </tr>
128
+ <tr>
129
+ <th scope="row" valign="top">
130
+ <label for="email_admin_changes"><?php _e('Admin Changes', 'pmpro');?>:</label>
131
+ </th>
132
+ <td>
133
+ <input type="checkbox" id="email_admin_changes" name="email_admin_changes" value="1" <?php if(!empty($email_admin_changes)) { ?>checked="checked"<?php } ?> />
134
+ <?php _e('when an admin changes a user\'s membership level through the dashboard.', 'pmpro');?>
135
+ </td>
136
+ </tr>
137
+ <tr>
138
+ <th scope="row" valign="top">
139
+ <label for="email_admin_cancels"><?php _e('Cancellation', 'pmpro');?>:</label>
140
+ </th>
141
+ <td>
142
+ <input type="checkbox" id="email_admin_cancels" name="email_admin_cancels" value="1" <?php if(!empty($email_admin_cancels)) { ?>checked="checked"<?php } ?> />
143
+ <?php _e('when a user cancels his or her account.', 'pmpro');?>
144
+ </td>
145
+ </tr>
146
+ <tr>
147
+ <th scope="row" valign="top">
148
+ <label for="email_admin_billing"><?php _e('Bill Updates', 'pmpro');?>:</label>
149
+ </th>
150
+ <td>
151
+ <input type="checkbox" id="email_admin_billing" name="email_admin_billing" value="1" <?php if(!empty($email_admin_billing)) { ?>checked="checked"<?php } ?> />
152
+ <?php _e('when a user updates his or her billing information.', 'pmpro');?>
153
+ </td>
154
+ </tr>
155
+ </tbody>
156
+ </table>
157
+
158
+ <h3><?php _e('Send members emails', 'pmpro');?>:</h3>
159
+
160
+ <table class="form-table">
161
+ <tbody>
162
+ <tr>
163
+ <th scope="row" valign="top">
164
+ <label for="email_admin_checkout"><?php _e('New Users', 'pmpro');?>:</label>
165
+ </th>
166
+ <td>
167
+ <input type="checkbox" id="email_member_notification" name="email_member_notification" value="1" <?php if(!empty($email_member_notification)) { ?>checked="checked"<?php } ?> />
168
+ <?php _e('Default WP notification email. (Recommended: Leave unchecked. Members will still get an email confirmation from PMPro after checkout.)', 'pmpro');?>
169
+ </td>
170
+ </tr>
171
+ </tbody>
172
+ </table>
173
+
174
+ <p class="submit">
175
+ <input name="savesettings" type="submit" class="button-primary" value="Save Settings" />
176
+ </p>
177
+ </form>
178
+
179
+ <?php
180
+ require_once(dirname(__FILE__) . "/admin_footer.php");
181
+ ?>
adminpages/functions.php ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
21
+ /*
22
+ Checks if PMPro settings are complete or if there are any errors.
23
+ */
24
+ function pmpro_checkLevelForStripeCompatibility($level = NULL)
25
+ {
26
+ $gateway = pmpro_getOption("gateway");
27
+ if($gateway == "stripe")
28
+ {
29
+ global $wpdb;
30
+
31
+ //check ALL the levels
32
+ if(empty($level))
33
+ {
34
+ $sqlQuery = "SELECT * FROM $wpdb->pmpro_membership_levels ORDER BY id ASC";
35
+ $levels = $wpdb->get_results($sqlQuery, OBJECT);
36
+ if(!empty($levels))
37
+ {
38
+ foreach($levels as $level)
39
+ {
40
+ /*
41
+ Stripe currently does not support:
42
+ * Trial Amounts > 0.
43
+ * Billing Limits.
44
+ */
45
+ if($level->trial_amount > 0 ||
46
+ $level->billing_limit > 0)
47
+ {
48
+ return false;
49
+ }
50
+ }
51
+ }
52
+ }
53
+ else
54
+ {
55
+ //need to look it up?
56
+ if(is_numeric($level))
57
+ $level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . esc_sql($level) . "' LIMIT 1");
58
+
59
+ //check this level
60
+ if($level->trial_amount > 0 ||
61
+ ($level->cycle_number > 0 && $level->cycle_period == "Day") ||
62
+ $level->billing_limit > 0)
63
+ {
64
+ return false;
65
+ }
66
+ }
67
+ }
68
+
69
+ return true;
70
+ }
71
+
72
+ /*
73
+ Checks if PMPro settings are complete or if there are any errors.
74
+ */
75
+ function pmpro_checkLevelForPayflowCompatibility($level = NULL)
76
+ {
77
+ $gateway = pmpro_getOption("gateway");
78
+ if($gateway == "payflowpro")
79
+ {
80
+ global $wpdb;
81
+
82
+ //check ALL the levels
83
+ if(empty($level))
84
+ {
85
+ $sqlQuery = "SELECT * FROM $wpdb->pmpro_membership_levels ORDER BY id ASC";
86
+ $levels = $wpdb->get_results($sqlQuery, OBJECT);
87
+ if(!empty($levels))
88
+ {
89
+ foreach($levels as $level)
90
+ {
91
+ /*
92
+ Payflow currently does not support:
93
+ * Trial Amounts > 0.
94
+ * Daily billing periods.
95
+ */
96
+
97
+ if($level->trial_amount > 0 ||
98
+ $level->cycle_number > 1)
99
+ {
100
+ return false;
101
+ }
102
+ }
103
+ }
104
+ }
105
+ else
106
+ {
107
+ //need to look it up?
108
+ if(is_numeric($level))
109
+ $level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . esc_sql($level) . "' LIMIT 1");
110
+
111
+ //check this level
112
+ if($level->trial_amount > 0 ||
113
+ $level->cycle_number > 1 ||
114
+ ($level->cycle_number == 1 && $level->cycle_period == "Day"))
115
+ {
116
+ return false;
117
+ }
118
+ }
119
+ }
120
+
121
+ return true;
122
+ }
123
+
124
+ /*
125
+ Checks if PMPro settings are complete or if there are any errors.
126
+ */
127
+ function pmpro_checkLevelForBraintreeCompatibility($level = NULL)
128
+ {
129
+ $gateway = pmpro_getOption("gateway");
130
+ if($gateway == "braintree")
131
+ {
132
+ global $wpdb;
133
+
134
+ //check ALL the levels
135
+ if(empty($level))
136
+ {
137
+ $sqlQuery = "SELECT * FROM $wpdb->pmpro_membership_levels ORDER BY id ASC";
138
+ $levels = $wpdb->get_results($sqlQuery, OBJECT);
139
+ if(!empty($levels))
140
+ {
141
+ foreach($levels as $level)
142
+ {
143
+ /*
144
+ Braintree currently does not support:
145
+ * Trial Amounts > 0.
146
+ * Daily or Weekly billing periods.
147
+ */
148
+ if($level->trial_amount > 0 ||
149
+ ($level->cycle_number > 0 && ($level->cycle_period == "Day" || $level->cycle_period == "Week")))
150
+ {
151
+ return false;
152
+ }
153
+ }
154
+ }
155
+ }
156
+ else
157
+ {
158
+ //need to look it up?
159
+ if(is_numeric($level))
160
+ $level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . esc_sql($level) . "' LIMIT 1");
161
+
162
+ //check this level
163
+ if($level->trial_amount > 0 ||
164
+ ($level->cycle_number > 0 && ($level->cycle_period == "Day" || $level->cycle_period == "Week")))
165
+ {
166
+ return false;
167
+ }
168
+ }
169
+ }
170
+
171
+ return true;
172
+ }
173
+
174
+ /*
175
+ Checks if PMPro settings are complete or if there are any errors.
176
+ */
177
+ function pmpro_checkLevelForTwoCheckoutCompatibility($level = NULL)
178
+ {
179
+ $gateway = pmpro_getOption("gateway");
180
+ if($gateway == "twocheckout")
181
+ {
182
+ global $wpdb;
183
+
184
+ //check ALL the levels
185
+ if(empty($level))
186
+ {
187
+ $sqlQuery = "SELECT * FROM $wpdb->pmpro_membership_levels ORDER BY id ASC";
188
+ $levels = $wpdb->get_results($sqlQuery, OBJECT);
189
+ if(!empty($levels))
190
+ {
191
+ foreach($levels as $level)
192
+ {
193
+ /*
194
+ 2Checkout currently does not support:
195
+ * Trial amounts less than or greater than the absolute value of amonthly recurring amount.
196
+ */
197
+ if(pmpro_isLevelTrial($level))
198
+ {
199
+ return false;
200
+ }
201
+ }
202
+ }
203
+ }
204
+ else
205
+ {
206
+ //need to look it up?
207
+ if(is_numeric($level))
208
+ $level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . esc_sql($level) . "' LIMIT 1");
209
+
210
+ //check this level
211
+ if(pmpro_isLevelTrial($level))
212
+ {
213
+ return false;
214
+ }
215
+ }
216
+ }
217
+
218
+ return true;
219
+ }
adminpages/membershiplevels.php CHANGED
@@ -1,1016 +1,615 @@
1
- <?php
2
- global $wpdb;
3
- $edit = $_REQUEST['edit'];
4
- $view = $_REQUEST['view'];
5
- $copy = $_REQUEST['copy'];
6
- $s = $_REQUEST['s'];
7
-
8
- //get/set settings
9
- global $pmpro_pages;
10
- if($_REQUEST['savesettings'])
11
- {
12
- $view = $_REQUEST['view'];
13
-
14
- if($view == "pages")
15
- {
16
- //page ids
17
- pmpro_setOption("account_page_id");
18
- pmpro_setOption("billing_page_id");
19
- pmpro_setOption("cancel_page_id");
20
- pmpro_setOption("checkout_page_id");
21
- pmpro_setOption("confirmation_page_id");
22
- pmpro_setOption("invoice_page_id");
23
- pmpro_setOption("levels_page_id");
24
-
25
- //update the pages array
26
- $pmpro_pages["account"] = pmpro_getOption("account_page_id");
27
- $pmpro_pages["billing"] = pmpro_getOption("billing_page_id");
28
- $pmpro_pages["cancel"] = pmpro_getOption("cancel_page_id");
29
- $pmpro_pages["checkout"] = pmpro_getOption("checkout_page_id");
30
- $pmpro_pages["confirmation"] = pmpro_getOption("confirmation_page_id");
31
- $pmpro_pages["invoice"] = pmpro_getOption("invoice_page_id");
32
- $pmpro_pages["levels"] = pmpro_getOption("levels_page_id");
33
- }
34
-
35
- if($view == "payment")
36
- {
37
- pmpro_setOption("sslseal");
38
-
39
- //gateway options
40
- pmpro_setOption("gateway");
41
- pmpro_setOption("gateway_environment");
42
- pmpro_setOption("gateway_email");
43
- pmpro_setOption("apiusername");
44
- pmpro_setOption("apipassword");
45
- pmpro_setOption("apisignature");
46
- pmpro_setOption("loginname");
47
- pmpro_setOption("transactionkey");
48
-
49
- //credit cards
50
- $pmpro_accepted_credit_cards = array();
51
- if($_REQUEST['creditcards_visa'])
52
- $pmpro_accepted_credit_cards[] = "Visa";
53
- if($_REQUEST['creditcards_mastercard'])
54
- $pmpro_accepted_credit_cards[] = "Mastercard";
55
- if($_REQUEST['creditcards_amex'])
56
- $pmpro_accepted_credit_cards[] = "American Express";
57
- if($_REQUEST['creditcards_discover'])
58
- $pmpro_accepted_credit_cards[] = "Discover";
59
-
60
- //tax
61
- pmpro_setOption("tax_state");
62
- pmpro_setOption("tax_rate");
63
-
64
- pmpro_setOption("accepted_credit_cards", implode(",", $pmpro_accepted_credit_cards));
65
- }
66
-
67
- if($view == "email")
68
- {
69
- //email options
70
- pmpro_setOption("from_email");
71
- pmpro_setOption("from_name");
72
- }
73
-
74
- if($view == "advanced")
75
- {
76
- //other settings
77
- pmpro_setOption("nonmembertext");
78
- pmpro_setOption("notloggedintext");
79
- pmpro_setOption("rsstext");
80
- pmpro_setOption("showexcerpts");
81
- pmpro_setOption("hideads");
82
- pmpro_setOption("hideadslevels");
83
- pmpro_setOption("redirecttosubscription");
84
-
85
- //captcha
86
- pmpro_setOption("recaptcha");
87
- pmpro_setOption("recaptcha_publickey");
88
- pmpro_setOption("recaptcha_privatekey");
89
-
90
- //tos
91
- pmpro_setOption("tospage");
92
-
93
- //footer link
94
- pmpro_setOption("hide_footer_link");
95
- }
96
- }
97
-
98
- $nonmembertext = pmpro_getOption("nonmembertext");
99
- $notloggedintext = pmpro_getOption("notloggedintext");
100
- $rsstext = pmpro_getOption("rsstext");
101
- $sslseal = pmpro_getOption("sslseal");
102
- $hideads = pmpro_getOption("hideads");
103
- $showexcerpts = pmpro_getOption("showexcerpts");
104
- $hideadslevels = pmpro_getOption("hideadslevels");
105
-
106
- if(is_multisite())
107
- $redirecttosubscription = pmpro_getOption("redirecttosubscription");
108
-
109
- $recaptcha = pmpro_getOption("recaptcha");
110
- $recaptcha_publickey = pmpro_getOption("recaptcha_publickey");
111
- $recaptcha_privatekey = pmpro_getOption("recaptcha_privatekey");
112
-
113
- $tospage = pmpro_getOption("tospage");
114
-
115
- $hide_footer_link = pmpro_getOption("hide_footer_link");
116
-
117
- $from_email = pmpro_getOption("from_email");
118
- $from_name = pmpro_getOption("from_name");
119
-
120
- $gateway = pmpro_getOption("gateway");
121
- $gateway_environment = pmpro_getOption("gateway_environment");
122
- $gateway_email = pmpro_getOption("gateway_email");
123
- $apiusername = pmpro_getOption("apiusername");
124
- $apipassword = pmpro_getOption("apipassword");
125
- $apisignature = pmpro_getOption("apisignature");
126
- $loginname = pmpro_getOption("loginname");
127
- $transactionkey = pmpro_getOption("transactionkey");
128
-
129
- $pmpro_accepted_credit_cards = pmpro_getOption("accepted_credit_cards");
130
-
131
- $tax_state = pmpro_getOption("tax_state");
132
- $tax_rate = pmpro_getOption("tax_rate");
133
-
134
- //default settings
135
- if(!$nonmembertext)
136
- {
137
- $nonmembertext = "This content is for !!levels!! members only. <a href=\"" . wp_login_url() . "?action=register\">Register here</a>.";
138
- pmpro_setOption("nonmembertext", $nonmembertext);
139
- }
140
- if(!$notloggedintext)
141
- {
142
- $notloggedintext = "Please <a href=\"" . wp_login_url( get_permalink() ) . "\">login</a> to view this content. (<a href=\"" . wp_login_url() . "?action=register\">Register here</a>.)";
143
- pmpro_setOption("notloggedintext", $notloggedintext);
144
- }
145
- if(!$rsstext)
146
- {
147
- $rsstext = "This content is for members only. Visit the site and log in/register to read.";
148
- pmpro_setOption("rsstext", $rsstext);
149
- }
150
- if(!$gateway_environment)
151
- {
152
- $gateway_environment = "sandbox";
153
- pmpro_setOption("gateway_environment", $gateway_environment);
154
- }
155
- if(!$pmpro_accepted_credit_cards)
156
- {
157
- $pmpro_accepted_credit_cards = "Visa,Mastercard,American Express,Discover";
158
- pmpro_setOption("accepted_credit_cards", $pmpro_accepted_credit_cards);
159
- }
160
-
161
- $pmpro_accepted_credit_cards = split(",", $pmpro_accepted_credit_cards);
162
-
163
- if(!$from_email)
164
- {
165
- $parsed = parse_url(home_url());
166
- $hostname = $parsed[host];
167
- $hostparts = split("\.", $hostname);
168
- $email_domain = $hostparts[count($hostparts) - 2] . "." . $hostparts[count($hostparts) - 1];
169
- $from_email = "wordpress@" . $email_domain;
170
- pmpro_setOption("from_email", $from_email);
171
- }
172
-
173
- if(!$from_name)
174
- {
175
- $from_name = "WordPress";
176
- pmpro_setOption("from_name", $from_name);
177
- }
178
-
179
-
180
- //are we generating pages?
181
- if($_REQUEST['createpages'])
182
- {
183
- global $pmpro_pages;
184
-
185
- $pages_created = array();
186
-
187
- //check the pages array
188
- foreach($pmpro_pages as $pmpro_page_name => $pmpro_page_id)
189
- {
190
- if(!$pmpro_page_id)
191
- {
192
- //no id set. create an array to store the page info
193
- $insert = array(
194
- 'post_title' => 'Membership ' . ucwords($pmpro_page_name),
195
- 'post_status' => 'publish',
196
- 'post_type' => 'page',
197
- 'post_content' => '[pmpro_' . $pmpro_page_name . ']',
198
- 'comment_status' => 'closed',
199
- 'ping_status' => 'closed'
200
- );
201
- //create the page
202
- $pmpro_pages[$pmpro_page_name] = wp_insert_post( $insert );
203
-
204
- //add besecure post option to pages that need it
205
- if(in_array($pmpro_page_name, array("billing", "checkout")))
206
- update_post_meta($pmpro_pages[$pmpro_page_name], "besecure", 1);
207
-
208
- //update the option too
209
- pmpro_setOption($pmpro_page_name . "_page_id", $pmpro_pages[$pmpro_page_name]);
210
- $pages_created[] = $pmpro_pages[$pmpro_page_name];
211
- }
212
- }
213
-
214
- if($pages_created)
215
- {
216
- $msg = true;
217
- $msgt = "The following pages have been created for you: " . implode(", ", $pages_created) . ".";
218
- }
219
- }
220
-
221
- //any messages?
222
- if(!$msg)
223
- $msg = $_REQUEST['msg'];
224
- if($msg === "1")
225
- $msgt = "Membership level added successfully.";
226
- elseif($msg === "-1")
227
- $msgt = "Error adding membership level.";
228
- elseif($msg === "2")
229
- $msgt = "Membership level updated successfully.";
230
- elseif($msg === "-2")
231
- $msgt = "Error updating membership level.";
232
- elseif($msg === "3")
233
- $msgt = "Membership level deleted successfully.";
234
- elseif($msg === "-3")
235
- $msgt = "Error deleting membership level.";
236
-
237
- global $pmpro_ready;
238
- $pmpro_ready = pmpro_is_ready();
239
- if(!$pmpro_ready)
240
- {
241
- global $pmpro_level_ready, $pmpro_gateway_ready, $pmpro_pages_ready;
242
- $view = $_REQUEST['view'];
243
- $edit = $_REQUEST['edit'];
244
- if(!$msg)
245
- $msg = -1;
246
- if(!$pmpro_level_ready && !$edit)
247
- $msgt .= " <a href=\"?page=pmpro-membershiplevels&edit=-1\">Add a membership level</a> to get started.";
248
- elseif($pmpro_level_ready && !$pmpro_pages_ready && $view != "pages")
249
- $msgt .= " <a href=\"?page=pmpro-membershiplevels&view=pages\">Setup the membership pages</a>.";
250
- elseif($pmpro_level_ready && $pmpro_pages_ready && !$pmpro_gateway_ready && $view != "payment")
251
- $msgt .= " <a href=\"?page=pmpro-membershiplevels&view=payment\">Setup your SSL certificate and payment gateway</a>.";
252
-
253
- if(!$msgt)
254
- $msg = false;
255
- }
256
-
257
- if($msg)
258
- {
259
- ?>
260
- <div id="message" class="<?php if($msg > 0) echo "updated fade"; else echo "error"; ?>"><p><?=$msgt?></p></div>
261
- <?php
262
- }
263
-
264
- ?>
265
- <div class="wrap pmpro_admin">
266
- <div class="pmpro_banner">
267
- <a class="pmpro_logo" title="Paid Memberships Pro - Membership Plugin for WordPress" target="_blank" href="<?=pmpro_https_filter("http://www.paidmembershipspro.com")?>"><img src="<?=PMPRO_URL?>/images/PaidMembershipsPro.gif" width="350" height="45" border="0" alt="Paid Memberships Pro(c) - All Rights Reserved" /></a>
268
- <div class="pmpro_tagline">Membership Plugin for WordPress</div>
269
-
270
- <div class="pmpro_meta"><a href="<?=pmpro_https_filter("http://www.paidmembershipspro.com")?>">Plugin Support</a> | <a href="http://www.paidmembershipspro.com/forums/">User Forum</a> | <strong>Version <?=PMPRO_VERSION?></strong></div>
271
- </div>
272
- <br style="clear:both;" />
273
-
274
- <?php
275
- //include(pmpro_https_filter("http://www.paidmembershipspro.com/notifications/?v=" . PMPRO_VERSION));
276
- ?>
277
- <div id="pmpro_notifications">
278
- </div>
279
- <script>
280
- jQuery.get('<?=pmpro_https_filter("http://www.paidmembershipspro.com/notifications/?v=" . PMPRO_VERSION)?>', function(data) {
281
- jQuery('#pmpro_notifications').html(data);
282
- });
283
- </script>
284
-
285
- <h3 class="nav-tab-wrapper">
286
- <a href="admin.php?page=pmpro-membershiplevels" class="nav-tab<?php if(!$view || $edit) { ?> nav-tab-active<?php } ?>">Membership Levels</a>
287
- <a href="admin.php?page=pmpro-membershiplevels&view=pages" class="nav-tab<?php if($view == 'pages') { ?> nav-tab-active<?php } ?>">Pages</a>
288
- <a href="admin.php?page=pmpro-membershiplevels&view=payment" class="nav-tab<?php if($view == 'payment') { ?> nav-tab-active<?php } ?>">SSL &amp; Payment Gateway</a>
289
- <a href="admin.php?page=pmpro-membershiplevels&view=email" class="nav-tab<?php if($view == 'email') { ?> nav-tab-active<?php } ?>">Email</a>
290
- <a href="admin.php?page=pmpro-membershiplevels&view=advanced" class="nav-tab<?php if($view == 'advanced') { ?> nav-tab-active<?php } ?>">Advanced</a>
291
- </h3>
292
-
293
- <?php
294
- if($edit)
295
- {
296
- ?>
297
-
298
- <h2>
299
- <?php
300
- if($edit > 0)
301
- echo "Edit Membership Level";
302
- else
303
- echo "Add New Membership Level";
304
- ?>
305
- </h2>
306
-
307
- <div>
308
- <?php
309
- // get the level...
310
- if($edit > 0)
311
- {
312
- $level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '$edit' LIMIT 1", OBJECT);
313
- $temp_id = $level->id;
314
- }
315
- elseif($copy > 0)
316
- {
317
- $level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '$copy' LIMIT 1", OBJECT);
318
- $temp_id = $level->id;
319
- $level->id = NULL;
320
- }
321
-
322
- // didn't find a membership level, let's add a new one...
323
- if(!$level) $edit = -1;
324
-
325
- // grab the categories for the given level...
326
- $level->categories = $wpdb->get_col("SELECT c.category_id
327
- FROM $wpdb->pmpro_memberships_categories c
328
- WHERE c.membership_id = '" . $temp_id . "'");
329
- if(!$level->categories)
330
- $level->categories = array();
331
- ?>
332
- <form action="<?=PMPRO_URL?>/services/pmpro-data.php?action=save_membershiplevel" method="post" enctype="multipart/form-data">
333
- <input name="saveid" type="hidden" value="<?=$edit?>" />
334
- <table class="form-table">
335
- <tbody>
336
- <tr>
337
- <th scope="row" valign="top"><label>ID:</label></th>
338
- <td><?=$level->id?></td>
339
- </tr>
340
-
341
- <tr>
342
- <th scope="row" valign="top"><label for="name">Name:</label></th>
343
- <td><input name="name" type="text" size="50" value="<?=str_replace("\"", "&quot;", stripslashes($level->name))?>" /></td>
344
- </tr>
345
-
346
- <tr>
347
- <th scope="row" valign="top"><label for="description">Description:</label></th>
348
- <td>
349
- <div id="poststuff" class="pmpro_description">
350
- <textarea rows="10" cols="80" name="description" id="description"><?=str_replace("\"", "&quot;", stripslashes($level->description))?></textarea>
351
- </div>
352
- </td>
353
- </tr>
354
- </tbody>
355
- </table>
356
-
357
- <h3 class="topborder">Billing Details</h3>
358
- <table class="form-table">
359
- <tbody>
360
- <tr>
361
- <th scope="row" valign="top"><label for="initial_payment">Initial Payment:</label></th>
362
- <td>$<input name="initial_payment" type="text" size="20" value="<?=str_replace("\"", "&quot;", stripslashes($level->initial_payment))?>" /> <small>The initial amount collected at registration.</small></td>
363
- </tr>
364
-
365
- <tr>
366
- <th scope="row" valign="top"><label>Recurring Subscription:</label></th>
367
- <td><input id="recurring" name="recurring" type="checkbox" value="yes" <?php if(pmpro_isLevelRecurring($level)) { echo "checked='checked'"; } ?> onclick="if(jQuery('#recurring').is(':checked')) { jQuery('.recurring_info').show(); if(jQuery('#custom_trial').is(':checked')) {jQuery('.trial_info').show();} else {jQuery('.trial_info').hide();} } else { jQuery('.recurring_info').hide();}" /> <small>Check if this level has a recurring subscription payment.</small></td>
368
- </tr>
369
-
370
- <tr class="recurring_info" <?php if(!pmpro_isLevelRecurring($level)) {?>style="display: none;"<?php } ?>>
371
- <th scope="row" valign="top"><label for="billing_amount">Billing Amount:</label></th>
372
- <td>
373
- $<input name="billing_amount" type="text" size="20" value="<?=str_replace("\"", "&quot;", stripslashes($level->billing_amount))?>" /> <small>per</small>
374
- <input id="cycle_number" name="cycle_number" type="text" size="10" value="<?=str_replace("\"", "&quot;", stripslashes($level->cycle_number))?>" />
375
- <select id="cycle_period" name="cycle_period" onchange="updateCyclePeriod();">
376
- <?php
377
- $cycles = array( 'Day(s)' => 'Day', 'Week(s)' => 'Week', 'Month(s)' => 'Month', 'Year(s)' => 'Year' );
378
- foreach ( $cycles as $name => $value ) {
379
- echo "<option value='$value'";
380
- if ( $level->cycle_period == $value ) echo " selected='selected'";
381
- echo ">$name</option>";
382
- }
383
- ?>
384
- </select>
385
- <br /><small>The amount to be billed one cycle after the initial payment.</small>
386
- <script>
387
- function updateCyclePeriod()
388
- {
389
- jQuery('#trial_cycle_period_select').val(jQuery('#cycle_period').val());
390
- jQuery('#trial_cycle_period').val(jQuery('#cycle_period').val());
391
- }
392
- </script>
393
- </td>
394
- </tr>
395
-
396
- <tr class="recurring_info" <?php if(!pmpro_isLevelRecurring($level)) {?>style="display: none;"<?php } ?>>
397
- <th scope="row" valign="top"><label for="billing_limit">Billing Cycle Limit:</label></th>
398
- <td>
399
- <input name="billing_limit" type="text" size="20" value="<?=$level->billing_limit?>" />
400
- <br /><small>The <strong>total</strong> number of billing cycles for this level, including the trial period (if applicable). Set to zero if membership is indefinite.</small>
401
- </td>
402
- </tr>
403
-
404
- <tr class="recurring_info" <?php if (!pmpro_isLevelRecurring($level)) echo "style='display:none;'";?>>
405
- <th scope="row" valign="top"><label>Custom Trial:</label></th>
406
- <td><input id="custom_trial" name="custom_trial" type="checkbox" value="yes" <?php if ( pmpro_isLevelTrial($level) ) { echo "checked='checked'"; } ?> onclick="jQuery('.trial_info').toggle();" /> Check to add a custom trial period.</td>
407
- </tr>
408
-
409
- <tr class="trial_info recurring_info" <?php if (!pmpro_isLevelTrial($level)) echo "style='display:none;'";?>>
410
- <th scope="row" valign="top"><label for="trial_amount">Trial Billing Amount:</label></th>
411
- <td>
412
- $<input name="trial_amount" type="text" size="20" value="<?=str_replace("\"", "&quot;", stripslashes($level->trial_amount))?>" />
413
- <small>for the first</small>
414
- <input name="trial_limit" type="text" size="10" value="<?=str_replace("\"", "&quot;", stripslashes($level->trial_limit))?>" />
415
- <small>subscription payments.</small>
416
- </td>
417
- </tr>
418
- </tbody>
419
- </table>
420
- <h3 class="topborder">Other Settings</h3>
421
- <table class="form-table">
422
- <tbody>
423
- <tr>
424
- <th scope="row" valign="top"><label>Disable New Signups:</label></th>
425
- <td><input name="disable_signups" type="checkbox" value="yes" <?php if($level->id && !$level->allow_signups) { ?>checked="checked"<?php } ?> /> Check to hide this level from the membership levels page and disable registration.</td>
426
- </tr>
427
- </tbody>
428
- </table>
429
- <h3 class="topborder">Content Settings</h3>
430
- <table class="form-table">
431
- <tbody>
432
- <tr>
433
- <th scope="row" valign="top"><label>Categories:</label></th>
434
- <td>
435
- <?php
436
- $categories = get_categories( array( 'hide_empty' => 0 ) );
437
- echo "<ul>";
438
- foreach ( $categories as $cat )
439
- {
440
- $checked = in_array( $cat->term_id, $level->categories ) ? "checked='checked'" : '';
441
- echo "<li><input name='membershipcategory_{$cat->term_id}' type='checkbox' value='yes' $checked /> {$cat->name}</li>\n";
442
- }
443
- echo "</ul>";
444
- ?>
445
- </td>
446
- </tr>
447
- </tbody>
448
- </table>
449
- <p class="submit topborder">
450
- <input name="save" type="submit" class="button-primary" value="Save Level" />
451
- <input name="cancel" type="button" value="Cancel" onclick="location.href='<?=home_url('/wp-admin/admin.php?page=pmpro-membershiplevels')?>';" />
452
- </p>
453
- </form>
454
- </div>
455
-
456
- <?php
457
- }
458
- elseif($view == 'pages')
459
- {
460
- ?>
461
- <form action="admin.php?page=pmpro-membershiplevels&view=pages" method="post" enctype="multipart/form-data">
462
- <h2>Pages</h2>
463
- <?php
464
- global $pmpro_pages_ready;
465
- if($pmpro_pages_ready)
466
- {
467
- ?>
468
- <p>Manage the WordPress pages assigned to each required Paid Memberships Pro page.</p>
469
- <?php
470
- }
471
- else
472
- {
473
- ?>
474
- <p>Assign the WordPress pages for each required Paid Memberships Pro page or <a href="?page=pmpro-membershiplevels&view=pages&createpages=1">click here to let us generate them for you</a>.</p>
475
- <?php
476
- }
477
- ?>
478
- <table class="form-table">
479
- <tbody>
480
- <tr>
481
- <th scope="row" valign="top">
482
- <label for="account_page_id">Account Page:</label>
483
- </th>
484
- <td>
485
- <?php
486
- wp_dropdown_pages(array("name"=>"account_page_id", "show_option_none"=>"-- Choose One --", "selected"=>$pmpro_pages[account]));
487
- ?>
488
- </td>
489
- <tr>
490
- <th scope="row" valign="top">
491
- <label for="billing_page_id">Billing Information Page:</label>
492
- </th>
493
- <td>
494
- <?php
495
- wp_dropdown_pages(array("name"=>"billing_page_id", "show_option_none"=>"-- Choose One --", "selected"=>$pmpro_pages[billing]));
496
- ?>
497
- </td>
498
- <tr>
499
- <th scope="row" valign="top">
500
- <label for="cancel_page_id">Cancel Page:</label>
501
- </th>
502
- <td>
503
- <?php
504
- wp_dropdown_pages(array("name"=>"cancel_page_id", "show_option_none"=>"-- Choose One --", "selected"=>$pmpro_pages[cancel]));
505
- ?>
506
- </td>
507
- </tr>
508
- <tr>
509
- <th scope="row" valign="top">
510
- <label for="cancel_page_id">Checkout Page:</label>
511
- </th>
512
- <td>
513
- <?php
514
- wp_dropdown_pages(array("name"=>"checkout_page_id", "show_option_none"=>"-- Choose One --", "selected"=>$pmpro_pages[checkout]));
515
- ?>
516
- </td>
517
- </tr>
518
- <tr>
519
- <th scope="row" valign="top">
520
- <label for="cancel_page_id">Confirmation Page:</label>
521
- </th>
522
- <td>
523
- <?php
524
- wp_dropdown_pages(array("name"=>"confirmation_page_id", "show_option_none"=>"-- Choose One --", "selected"=>$pmpro_pages[confirmation]));
525
- ?>
526
- </td>
527
- </tr>
528
- <tr>
529
- <th scope="row" valign="top">
530
- <label for="cancel_page_id">Invoice Page:</label>
531
- </th>
532
- <td>
533
- <?php
534
- wp_dropdown_pages(array("name"=>"invoice_page_id", "show_option_none"=>"-- Choose One --", "selected"=>$pmpro_pages[invoice]));
535
- ?>
536
- </td>
537
- </tr>
538
- <tr>
539
- <th scope="row" valign="top">
540
- <label for="cancel_page_id">Levels Page:</label>
541
- </th>
542
- <td>
543
- <?php
544
- wp_dropdown_pages(array("name"=>"levels_page_id", "show_option_none"=>"-- Choose One --", "selected"=>$pmpro_pages[levels]));
545
- ?>
546
- </td>
547
- </tr>
548
- </tbody>
549
- </table>
550
- <p class="submit">
551
- <input name="savesettings" type="submit" class="button-primary" value="Save Settings" />
552
- </p>
553
- </form>
554
- <?php
555
- }
556
- elseif($view == 'payment')
557
- {
558
- ?>
559
- <form action="admin.php?page=pmpro-membershiplevels&view=payment" method="post" enctype="multipart/form-data">
560
- <h2>SSL &amp; Payment Gateway Settings</h2>
561
-
562
- <p>Learn more about <a title="Paid Memberships Pro - SSL Settings" target="_blank" href="http://www.paidmembershipspro.com/support/initial-plugin-setup/ssl/">SSL</a> or <a title="Paid Memberships Pro - Payment Gateway Settings" target="_blank" href="http://www.paidmembershipspro.com/support/initial-plugin-setup/payment-gateway/">Payment Gateway Settings</a>.</p>
563
-
564
- <table class="form-table">
565
- <tbody>
566
- <tr>
567
- <th scope="row" valign="top">
568
- <label for="sslseal">SSL Seal Code:</label>
569
- </th>
570
- <td>
571
- <textarea name="sslseal" rows="3" cols="80"><?=stripslashes($sslseal)?></textarea>
572
- </td>
573
- </tr>
574
- <tr>
575
- <th scope="row" valign="top">
576
- <label for="gateway">Payment Gateway:</label>
577
- </th>
578
- <td>
579
- <select id="gateway" name="gateway" onchange="pmpro_changeGateway(jQuery(this).val());">
580
- <option value="">-- choose one --</option>
581
- <option value="paypal" <?php if($gateway == "paypal") { ?>selected="selected"<?php } ?>>PayPal</option>
582
- <option value="authorizenet" <?php if($gateway == "authorizenet") { ?>selected="selected"<?php } ?>>Authorize.net</option>
583
- </select>
584
- </td>
585
- </tr>
586
- <tr>
587
- <th scope="row" valign="top">
588
- <label for="gateway_environment">Gateway Environment:</label>
589
- </th>
590
- <td>
591
- <select name="gateway_environment">
592
- <option value="sandbox" <?php if($gateway_environment == "sandbox") { ?>selected="selected"<?php } ?>>Sandbox/Testing</option>
593
- <option value="live" <?php if($gateway_environment == "live") { ?>selected="selected"<?php } ?>>Live/Production</option>
594
- </select>
595
- <script>
596
- function pmpro_changeGateway(gateway)
597
- {
598
- //hide all gateway options
599
- jQuery('tr.gateway').hide();
600
- jQuery('tr.gateway_'+gateway).show();
601
- }
602
- pmpro_changeGateway(jQuery().val('#gateway'));
603
- </script>
604
- </td>
605
- </tr>
606
- <tr class="gateway gateway_paypal" <?php if($gateway != "paypal") { ?>style="display: none;"<?php } ?>>
607
- <th scope="row" valign="top">
608
- <label for="gateway_email">Gateway Account Email:</label>
609
- </th>
610
- <td>
611
- <input type="text" name="gateway_email" size="60" value="<?=$gateway_email?>" />
612
- </td>
613
- </tr>
614
- <tr class="gateway gateway_paypal" <?php if($gateway != "paypal") { ?>style="display: none;"<?php } ?>>
615
- <th scope="row" valign="top">
616
- <label for="apiusername">API Username:</label>
617
- </th>
618
- <td>
619
- <input type="text" name="apiusername" size="60" value="<?=$apiusername?>" />
620
- </td>
621
- </tr>
622
- <tr class="gateway gateway_paypal" <?php if($gateway != "paypal") { ?>style="display: none;"<?php } ?>>
623
- <th scope="row" valign="top">
624
- <label for="apipassword">API Password:</label>
625
- </th>
626
- <td>
627
- <input type="text" name="apipassword" size="60" value="<?=$apipassword?>" />
628
- </td>
629
- </tr>
630
- <tr class="gateway gateway_paypal" <?php if($gateway != "paypal") { ?>style="display: none;"<?php } ?>>
631
- <th scope="row" valign="top">
632
- <label for="apisignature">API Signature:</label>
633
- </th>
634
- <td>
635
- <input type="text" name="apisignature" size="60" value="<?=$apisignature?>" />
636
- </td>
637
- </tr>
638
- <tr class="gateway gateway_authorizenet" <?php if($gateway != "authorizenet") { ?>style="display: none;"<?php } ?>>
639
- <th scope="row" valign="top">
640
- <label for="loginname">Login Name:</label>
641
- </th>
642
- <td>
643
- <input type="text" name="loginname" size="60" value="<?=$loginname?>" />
644
- </td>
645
- </tr>
646
- <tr class="gateway gateway_authorizenet" <?php if($gateway != "authorizenet") { ?>style="display: none;"<?php } ?>>
647
- <th scope="row" valign="top">
648
- <label for="transactionkey">Transaction Key:</label>
649
- </th>
650
- <td>
651
- <input type="text" name="transactionkey" size="60" value="<?=$transactionkey?>" />
652
- </td>
653
- </tr>
654
- <tr>
655
- <th scope="row" valign="top">
656
- <label for="creditcards">Accepted Credit Card Types</label>
657
- </th>
658
- <td>
659
- <input type="checkbox" name="creditcards_visa" value="1" <?php if(in_array("Visa", $pmpro_accepted_credit_cards)) { ?>checked="checked"<?php } ?> /> Visa<br />
660
- <input type="checkbox" name="creditcards_mastercard" value="1" <?php if(in_array("Mastercard", $pmpro_accepted_credit_cards)) { ?>checked="checked"<?php } ?> /> Mastercard<br />
661
- <input type="checkbox" name="creditcards_amex" value="1" <?php if(in_array("American Express", $pmpro_accepted_credit_cards)) { ?>checked="checked"<?php } ?> /> American Express<br />
662
- <input type="checkbox" name="creditcards_discover" value="1" <?php if(in_array("Discover", $pmpro_accepted_credit_cards)) { ?>checked="checked"<?php } ?> /> Discover<br />
663
- </td>
664
- </tr>
665
- <tr>
666
- <th scope="row" valign="top">
667
- <label for="tax">Sales Tax <small>(optional)</small></label>
668
- </th>
669
- <td>
670
- Tax State:
671
- <input type="text" name="tax_state" size="4" value="<?=$tax_state?>" /> <small>(abbreviation, e.g. "PA")</small>
672
- &nbsp; Tax Rate:
673
- <input type="text" name="tax_rate" size="10" value="<?=$tax_rate?>" /> <small>(decimal, e.g. "0.06")</small>
674
- <p><small>If values are given, tax will be applied for any members ordering from the selected state. For more complex tax rules, use the "pmpro_tax" filter.</small></p>
675
- </td>
676
- </tr>
677
- </tbody>
678
- </table>
679
- <p class="submit">
680
- <input name="savesettings" type="submit" class="button-primary" value="Save Settings" />
681
- </p>
682
- </form>
683
- <?php
684
- }
685
- elseif($view == 'email')
686
- {
687
- ?>
688
- <form action="admin.php?page=pmpro-membershiplevels&view=email" method="post" enctype="multipart/form-data">
689
- <h2>Email Settings</h2>
690
- <p>By default, system generated emails are sent from <em><strong>wordpress@yourdomain.com</strong></em>. You can update this from address using the fields below.</p>
691
-
692
- <p>To modify the appearance of system generated emails, add the files <em>email_header.html</em> and <em>email_footer.html</em> to your theme's directory. This will modify both the WordPress default messages as well as messages generated by Paid Memberships Pro. <a title="Paid Memberships Pro - Member Communications" target="_blank" href="http://www.paidmembershipspro.com/support/member-communications/">Click here to learn more about Paid Memberships Pro emails</a>.</p>
693
-
694
- <table class="form-table">
695
- <tbody>
696
- <tr>
697
- <th scope="row" valign="top">
698
- <label for="from_email">From Email:</label>
699
- </th>
700
- <td>
701
- <input type="text" name="from_email" size="60" value="<?=$from_email?>" />
702
- </td>
703
- </tr>
704
- <tr>
705
- <th scope="row" valign="top">
706
- <label for="from_name">From Name:</label>
707
- </th>
708
- <td>
709
- <input type="text" name="from_name" size="60" value="<?=$from_name?>" />
710
- </td>
711
- </tr>
712
- </tbody>
713
- </table>
714
- <p class="submit">
715
- <input name="savesettings" type="submit" class="button-primary" value="Save Settings" />
716
- </p>
717
- </form>
718
- <?php
719
- }
720
- elseif($view == 'advanced')
721
- {
722
- ?>
723
- <form action="admin.php?page=pmpro-membershiplevels&view=advanced" method="post" enctype="multipart/form-data">
724
- <h2>Advanced Settings</h2>
725
-
726
- <table class="form-table">
727
- <tbody>
728
- <tr>
729
- <th scope="row" valign="top">
730
- <label for="nonmembertext">Message for Logged-in Non-members:</label>
731
- </th>
732
- <td>
733
- <textarea name="nonmembertext" rows="3" cols="80"><?=stripslashes($nonmembertext)?></textarea><br />
734
- <small class="litegray">This message replaces the post content for non-members. Available variables: !!levels!!, !!referrer!!</small>
735
- </td>
736
- </tr>
737
- <tr>
738
- <th scope="row" valign="top">
739
- <label for="notloggedintext">Message for Logged-out Users:</label>
740
- </th>
741
- <td>
742
- <textarea name="notloggedintext" rows="3" cols="80"><?=stripslashes($notloggedintext)?></textarea><br />
743
- <small class="litegray">This message replaces the post content for logged-out visitors.</small>
744
- </td>
745
- </tr>
746
- <tr>
747
- <th scope="row" valign="top">
748
- <label for="rsstext">Message for RSS Feed:</label>
749
- </th>
750
- <td>
751
- <textarea name="rsstext" rows="3" cols="80"><?=stripslashes($rsstext)?></textarea><br />
752
- <small class="litegray">This message replaces the post content in RSS feeds.</small>
753
- </td>
754
- </tr>
755
-
756
- <tr>
757
- <th scope="row" valign="top">
758
- <label for="showexcerpts">Show Excerpts to Non-Members?</label>
759
- </th>
760
- <td>
761
- <select id="showexcerpts" name="showexcerpts">
762
- <option value="0" <?php if(!$showexcerpts) { ?>selected="selected"<?php } ?>>No - Hide excerpts.</option>
763
- <option value="1" <?php if($showexcerpts == 1) { ?>selected="selected"<?php } ?>>Yes - Show excerpts.</option>
764
- </select>
765
- </td>
766
- </tr>
767
- <tr>
768
- <th scope="row" valign="top">
769
- <label for="hideads">Hide Ads From Members?</label>
770
- </th>
771
- <td>
772
- <select id="hideads" name="hideads" onchange="pmpro_updateHideAdsTRs();">
773
- <option value="0" <?php if(!$hideads) { ?>selected="selected"<?php } ?>>No</option>
774
- <option value="1" <?php if($hideads == 1) { ?>selected="selected"<?php } ?>>Hide Ads From All Members</option>
775
- <option value="2" <?php if($hideads == 2) { ?>selected="selected"<?php } ?>>Hide Ads From Certain Members</option>
776
- </select>
777
- </td>
778
- </tr>
779
- <tr id="hideads_explanation" <?php if($hideads < 2) { ?>style="display: none;"<?php } ?>>
780
- <th scope="row" valign="top">&nbsp;</th>
781
- <td>
782
- <p class="top0em">Ads from the following plugins will be automatically turned off: <em>Easy Adsense</em>, ...</p>
783
- <p>To hide ads in your template code, use code like the following:</p>
784
- <pre lang="PHP">
785
- if(pmpro_displayAds())
786
- {
787
- //insert ad code here
788
- }
789
- </pre>
790
- </td>
791
- </tr>
792
- <tr id="hideadslevels_tr" <?php if($hideads != 2) { ?>style="display: none;"<?php } ?>>
793
- <th scope="row" valign="top">
794
- <label for="hideadslevels">Choose Levels to Hide Ads From:</label>
795
- </th>
796
- <td>
797
- <div class="checkbox_box" <?php if(count($levels) > 5) { ?>style="height: 100px; overflow: auto;"<?php } ?>>
798
- <?php
799
- $hideadslevels = pmpro_getOption("hideadslevels");
800
- if(!is_array($hideadslevels))
801
- $hideadslevels = split(",", $hideadslevels);
802
-
803
- $sqlQuery = "SELECT * FROM $wpdb->pmpro_membership_levels ";
804
- $levels = $wpdb->get_results($sqlQuery, OBJECT);
805
- foreach($levels as $level)
806
- {
807
- ?>
808
- <div class="clickable"><input type="checkbox" id="hideadslevels_<?=$level->id?>" name="hideadslevels[]" value="<?=$level->id?>" <?php if(in_array($level->id, $hideadslevels)) { ?>checked="checked"<?php } ?>> <?=$level->name?></div>
809
- <?php
810
- }
811
- ?>
812
- </div>
813
- <script>
814
- jQuery('.checkbox_box input').click(function(event) {
815
- event.stopPropagation()
816
- });
817
-
818
- jQuery('.checkbox_box div.clickable').click(function() {
819
- var checkbox = jQuery(this).find(':checkbox');
820
- checkbox.attr('checked', !checkbox.attr('checked'));
821
- });
822
- </script>
823
- </td>
824
- </tr>
825
- <?php if(is_multisite()) { ?>
826
- <tr>
827
- <th scope="row" valign="top">
828
- <label for="redirecttosubscription">Redirect all traffic from registration page to /susbcription/?: <em>(multisite only)</em></label>
829
- </th>
830
- <td>
831
- <select id="redirecttosubscription" name="redirecttosubscription">
832
- <option value="0" <?php if(!$redirecttosubscription) { ?>selected="selected"<?php } ?>>No</option>
833
- <option value="1" <?php if($redirecttosubscription == 1) { ?>selected="selected"<?php } ?>>Yes</option>
834
- </select>
835
- </td>
836
- </tr>
837
- <?php } ?>
838
- <tr>
839
- <th scope="row" valign="top">
840
- <label for="recaptcha">Use reCAPTCHA?:</label>
841
- </th>
842
- <td>
843
- <select id="recaptcha" name="recaptcha" onchange="pmpro_updateRecaptchaTRs();">
844
- <option value="0" <?php if(!$recaptcha) { ?>selected="selected"<?php } ?>>No</option>
845
- <option value="1" <?php if($recaptcha == 1) { ?>selected="selected"<?php } ?>>Yes - Free memberships only.</option>
846
- <option value="2" <?php if($recaptcha == 2) { ?>selected="selected"<?php } ?>>Yes - All memberships.</option>
847
- </select><br />
848
- <small>A free reCAPTCHA key is required. <a href="https://www.google.com/recaptcha/admin/create">Click here to signup for reCAPTCHA</a>.</small>
849
- </td>
850
- </tr>
851
- <tr id="recaptcha_tr" <?php if(!$recaptcha) { ?>style="display: none;"<?php } ?>>
852
- <th scope="row" valign="top">&nbsp;</th>
853
- <td>
854
- <label for="recaptcha_publickey">reCAPTCHA Public Key:</label>
855
- <input type="text" name="recaptcha_publickey" size="60" value="<?=$recaptcha_publickey?>" />
856
- <br /><br />
857
- <label for="recaptcha_privatekey">reCAPTCHA Private Key:</label>
858
- <input type="text" name="recaptcha_privatekey" size="60" value="<?=$recaptcha_privatekey?>" />
859
- </td>
860
- </tr>
861
- <tr>
862
- <th scope="row" valign="top">
863
- <label for="tospage">Require Terms of Service on signups?</label>
864
- </th>
865
- <td>
866
- <?php
867
- wp_dropdown_pages(array("name"=>"tospage", "show_option_none"=>"No", "selected"=>$tospage));
868
- ?>
869
- <br />
870
- <small>If yes, create a WordPress page containing your TOS agreement and assign it using the dropdown above.</small>
871
- </td>
872
- </tr>
873
-
874
- <?php /*
875
- <tr>
876
- <th scope="row" valign="top">
877
- <label for="hide_footer_link">Hide the PMPro Link in the Footer?</label>
878
- </th>
879
- <td>
880
- <select id="hide_footer_link" name="hide_footer_link">
881
- <option value="0" <?php if(!$hide_footer_link) { ?>selected="selected"<?php } ?>>No - Leave the link. (Thanks!)</option>
882
- <option value="1" <?php if($hide_footer_link == 1) { ?>selected="selected"<?php } ?>>Yes - Hide the link.</option>
883
- </select>
884
- </td>
885
- </tr>
886
- */ ?>
887
- </tbody>
888
- </table>
889
- <script>
890
- function pmpro_updateHideAdsTRs()
891
- {
892
- var hideads = jQuery('#hideads').val();
893
- if(hideads == 2)
894
- {
895
- jQuery('#hideadslevels_tr').show();
896
- }
897
- else
898
- {
899
- jQuery('#hideadslevels_tr').hide();
900
- }
901
-
902
- if(hideads > 0)
903
- {
904
- jQuery('#hideads_explanation').show();
905
- }
906
- else
907
- {
908
- jQuery('#hideads_explanation').hide();
909
- }
910
- }
911
- pmpro_updateHideAdsTRs();
912
-
913
- function pmpro_updateRecaptchaTRs()
914
- {
915
- var recaptcha = jQuery('#recaptcha').val();
916
- if(recaptcha > 0)
917
- {
918
- jQuery('#recaptcha_tr').show();
919
- }
920
- else
921
- {
922
- jQuery('#recaptcha_tr').hide();
923
- }
924
- }
925
- pmpro_updateRecaptchaTRs();
926
- </script>
927
-
928
- <p class="submit">
929
- <input name="savesettings" type="submit" class="button-primary" value="Save Settings" />
930
- </p>
931
- </form>
932
- <?php
933
- }
934
- else
935
- {
936
- ?>
937
-
938
- <h2>Membership Levels <a href="admin.php?page=pmpro-membershiplevels&edit=-1" class="button add-new-h2">Add New Level</a></h2>
939
- <form id="posts-filter" method="get" action="">
940
- <p class="search-box">
941
- <label class="screen-reader-text" for="post-search-input">Search Levels:</label>
942
- <input type="hidden" name="page" value="pmpro-membershiplevels" />
943
- <input id="post-search-input" type="text" value="<?=$s?>" name="s" size="30" />
944
- <input class="button" type="submit" value="Search Levels" id="search-submit "/>
945
- </p>
946
- </form>
947
-
948
- <br class="clear" />
949
-
950
- <table class="widefat">
951
- <thead>
952
- <tr>
953
- <th>ID</th>
954
- <th>Name</th>
955
- <th>Initial Payment</th>
956
- <th>Billing Cycle</th>
957
- <th>Trial Cycle</th>
958
- <th>Allow Signups</th>
959
- <th></th>
960
- <th></th>
961
- <th></th>
962
- </tr>
963
- </thead>
964
- <tbody>
965
- <?php
966
- $sqlQuery = "SELECT * FROM $wpdb->pmpro_membership_levels ";
967
- if($s)
968
- $sqlQuery .= "WHERE name LIKE '%$s%' ";
969
- $sqlQuery .= "ORDER BY id ASC";
970
-
971
- $levels = $wpdb->get_results($sqlQuery, OBJECT);
972
-
973
- foreach($levels as $level)
974
- {
975
- ?>
976
- <tr <?php if(!$level->allow_signups) { ?>class="pmpro_gray"<?php } ?>>
977
- <td><?=$level->id?></td>
978
- <td><?=$level->name?></td>
979
- <td>
980
- <?php if(pmpro_isLevelFree($level)) { ?>
981
- FREE
982
- <?php } else { ?>
983
- $<?=$level->initial_payment?>
984
- <?php } ?>
985
- </td>
986
- <td>
987
- <?php if(!pmpro_isLevelRecurring($level)) { ?>
988
- --
989
- <?php } else { ?>
990
- $<?=$level->billing_amount?> every <?=$level->cycle_number.' '.sornot($level->cycle_period,$level->cycle_number)?>
991
-
992
- <?php if($level->billing_limit) { ?>(for <?=$level->billing_limit?> <?=sornot($level->cycle_period,$level->cycle_number)?>)<?php } ?>
993
-
994
- <?php } ?>
995
- </td>
996
- <td>
997
- <?php if(!pmpro_isLevelTrial($level)) { ?>
998
- --
999
- <?php } else { ?>
1000
- $<?=$level->trial_amount?> for <?=$level->trial_limit?> <?=sornot("payment",$level->trial_limit)?>
1001
- <?php } ?>
1002
- </td>
1003
- <td><?php if($level->allow_signups) { ?>Yes<?php } else { ?>No<?php } ?></td>
1004
- <td align="center"><a href="admin.php?page=pmpro-membershiplevels&edit=<?=$level->id?>" class="edit">edit</a></td>
1005
- <td align="center"><a href="admin.php?page=pmpro-membershiplevels&copy=<?=$level->id?>&edit=-1" class="edit">copy</a></td>
1006
- <td align="center"><a href="javascript: askfirst('Are you sure you want to delete membership level <?=$level->name?>? All subscriptions will be canceled.','<?=PMPRO_URL?>/services/pmpro-data.php?action=delete_membership_level&deleteid=<?=$level->id?>'); void(0);" class="delete">delete</a></td>
1007
- </tr>
1008
- <?php
1009
- }
1010
- ?>
1011
- </tbody>
1012
- </table>
1013
- <?php
1014
- }
1015
- ?>
1016
- </div>
1
+ <?php
2
+ //only admins can get this
3
+ if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_membershiplevels")))
4
+ {
5
+ die(__("You do not have permissions to perform this action.", "pmpro"));
6
+ }
7
+
8
+ global $wpdb, $msg, $msgt, $pmpro_currency_symbol;
9
+
10
+ //some vars
11
+ $gateway = pmpro_getOption("gateway");
12
+ global $pmpro_stripe_error, $pmpro_braintree_error, $pmpro_payflow_error, $pmpro_twocheckout_error, $wp_version;
13
+
14
+ if(isset($_REQUEST['edit']))
15
+ $edit = $_REQUEST['edit'];
16
+ else
17
+ $edit = false;
18
+ if(isset($_REQUEST['copy']))
19
+ $copy = $_REQUEST['copy'];
20
+ if(isset($_REQUEST['s']))
21
+ $s = $_REQUEST['s'];
22
+ else
23
+ $s = "";
24
+
25
+ if(isset($_REQUEST['action']))
26
+ $action = $_REQUEST['action'];
27
+ else
28
+ $action = false;
29
+
30
+ if(isset($_REQUEST['saveandnext']))
31
+ $saveandnext = $_REQUEST['saveandnext'];
32
+
33
+ if(isset($_REQUEST['saveid']))
34
+ $saveid = $_REQUEST['saveid'];
35
+ if(isset($_REQUEST['deleteid']))
36
+ $deleteid = $_REQUEST['deleteid'];
37
+
38
+ if($action == "save_membershiplevel")
39
+ {
40
+ $ml_name = addslashes($_REQUEST['name']);
41
+ $ml_description = $_REQUEST['description'];
42
+ $ml_confirmation = $_REQUEST['confirmation'];
43
+ $ml_initial_payment = addslashes($_REQUEST['initial_payment']);
44
+ if(!empty($_REQUEST['recurring']))
45
+ $ml_recurring = 1;
46
+ else
47
+ $ml_recurring = 0;
48
+ $ml_billing_amount = addslashes($_REQUEST['billing_amount']);
49
+ $ml_cycle_number = addslashes($_REQUEST['cycle_number']);
50
+ $ml_cycle_period = addslashes($_REQUEST['cycle_period']);
51
+ $ml_billing_limit = addslashes($_REQUEST['billing_limit']);
52
+ if(!empty($_REQUEST['custom_trial']))
53
+ $ml_custom_trial = 1;
54
+ else
55
+ $ml_custom_trial = 0;
56
+ $ml_trial_amount = addslashes($_REQUEST['trial_amount']);
57
+ $ml_trial_limit = addslashes($_REQUEST['trial_limit']);
58
+ if(!empty($_REQUEST['expiration']))
59
+ $ml_expiration = 1;
60
+ else
61
+ $ml_expiration = 0;
62
+ $ml_expiration_number = addslashes($_REQUEST['expiration_number']);
63
+ $ml_expiration_period = addslashes($_REQUEST['expiration_period']);
64
+ $ml_categories = array();
65
+
66
+ //reversing disable to allow here
67
+ if(empty($_REQUEST['disable_signups']))
68
+ $ml_allow_signups = 1;
69
+ else
70
+ $ml_allow_signups = 0;
71
+
72
+ foreach ( $_REQUEST as $key => $value )
73
+ {
74
+ if ( $value == 'yes' && preg_match( '/^membershipcategory_(\d+)$/i', $key, $matches ) )
75
+ {
76
+ $ml_categories[] = $matches[1];
77
+ }
78
+ }
79
+
80
+ //clearing out values if checkboxes aren't checked
81
+ if(empty($ml_recurring))
82
+ {
83
+ $ml_billing_amount = $ml_cycle_number = $ml_cycle_period = $ml_billing_limit = $ml_trial_amount = $ml_trial_limit = 0;
84
+ }
85
+ elseif(empty($ml_custom_trial))
86
+ {
87
+ $ml_trial_amount = $ml_trial_limit = 0;
88
+ }
89
+ if(empty($ml_expiration))
90
+ {
91
+ $ml_expiration_number = $ml_expiration_period = 0;
92
+ }
93
+
94
+ if($saveid > 0)
95
+ {
96
+ $sqlQuery = " UPDATE {$wpdb->pmpro_membership_levels}
97
+ SET name = '" . esc_sql($ml_name) . "',
98
+ description = '" . esc_sql($ml_description) . "',
99
+ confirmation = '" . esc_sql($ml_confirmation) . "',
100
+ initial_payment = '" . esc_sql($ml_initial_payment) . "',
101
+ billing_amount = '" . esc_sql($ml_billing_amount) . "',
102
+ cycle_number = '" . esc_sql($ml_cycle_number) . "',
103
+ cycle_period = '" . esc_sql($ml_cycle_period) . "',
104
+ billing_limit = '" . esc_sql($ml_billing_limit) . "',
105
+ trial_amount = '" . esc_sql($ml_trial_amount) . "',
106
+ trial_limit = '" . esc_sql($ml_trial_limit) . "',
107
+ expiration_number = '" . esc_sql($ml_expiration_number) . "',
108
+ expiration_period = '" . esc_sql($ml_expiration_period) . "',
109
+ allow_signups = '" . esc_sql($ml_allow_signups) . "'
110
+ WHERE id = '$saveid' LIMIT 1;";
111
+ $wpdb->query($sqlQuery);
112
+
113
+ pmpro_updateMembershipCategories( $saveid, $ml_categories );
114
+ if(!mysql_errno())
115
+ {
116
+ $edit = false;
117
+ $msg = 2;
118
+ $msgt = __("Membership level updated successfully.", "pmpro");
119
+ }
120
+ else
121
+ {
122
+ $msg = -2;
123
+ $msg = true;
124
+ $msgt = __("Error updating membership level.", "pmpro");
125
+ }
126
+ }
127
+ else
128
+ {
129
+ $sqlQuery = " INSERT INTO {$wpdb->pmpro_membership_levels}
130
+ ( name, description, confirmation, initial_payment, billing_amount, cycle_number, cycle_period, billing_limit, trial_amount, trial_limit, expiration_number, expiration_period, allow_signups)
131
+ VALUES
132
+ ( '" . esc_sql($ml_name) . "', '" . esc_sql($ml_description) . "', '" . esc_sql($ml_confirmation) . "', '" . esc_sql($ml_initial_payment) . "', '" . esc_sql($ml_billing_amount) . "', '" . esc_sql($ml_cycle_number) . "', '" . esc_sql($ml_cycle_period) . "', '" . esc_sql($ml_billing_limit) . "', '" . esc_sql($ml_trial_amount) . "', '" . esc_sql($ml_trial_limit) . "', '" . esc_sql($ml_expiration_number) . "', '" . esc_sql($ml_expiration_period) . "', '" . esc_sql($ml_allow_signups) . "' )";
133
+ $wpdb->query($sqlQuery);
134
+ if(!mysql_errno())
135
+ {
136
+ $saveid = $wpdb->insert_id;
137
+ pmpro_updateMembershipCategories( $saveid, $ml_categories );
138
+
139
+ $edit = false;
140
+ $msg = 1;
141
+ $msgt = __("Membership level added successfully.", "pmpro");
142
+ }
143
+ else
144
+ {
145
+ $msg = -1;
146
+ $msgt = __("Error adding membership level.", "pmpro");
147
+ }
148
+ }
149
+
150
+ do_action("pmpro_save_membership_level", $saveid);
151
+ }
152
+ elseif($action == "delete_membership_level")
153
+ {
154
+ global $wpdb;
155
+
156
+ $ml_id = $_REQUEST['deleteid'];
157
+
158
+ if($ml_id > 0)
159
+ {
160
+ do_action("pmpro_delete_membership_level", $ml_id);
161
+
162
+ //remove any categories from the ml
163
+ $sqlQuery = "DELETE FROM $wpdb->pmpro_memberships_categories WHERE membership_id = '$ml_id'";
164
+ $r1 = $wpdb->query($sqlQuery);
165
+
166
+ //cancel any subscriptions to the ml
167
+ $r2 = true;
168
+ $user_ids = $wpdb->get_col("SELECT user_id FROM $wpdb->pmpro_memberships_users WHERE membership_id = '$ml_id' AND status = 'active'");
169
+ foreach($user_ids as $user_id)
170
+ {
171
+ //change there membership level to none. that will handle the cancel
172
+ if(pmpro_changeMembershipLevel(0, $user_id))
173
+ {
174
+ //okay
175
+ }
176
+ else
177
+ {
178
+ //couldn't delete the subscription
179
+ //we should probably notify the admin
180
+ $pmproemail = new PMProEmail();
181
+ $pmproemail->data = array("body"=>"<p>" . sprintf(__("There was an error canceling the subscription for user with ID=%d. You will want to check your payment gateway to see if their subscription is still active.", "pmpro"), $user_id) . "</p>");
182
+ $last_order = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_orders WHERE user_id = '" . $user_id . "' ORDER BY timestamp DESC LIMIT 1");
183
+ if($last_order)
184
+ $pmproemail->data["body"] .= "<p>" . __("Last Invoice", "pmpro") . ":<br />" . nl2br(var_export($last_order, true)) . "</p>";
185
+ $pmproemail->sendEmail(get_bloginfo("admin_email"));
186
+
187
+ $r2 = false;
188
+ }
189
+ }
190
+
191
+ //delete the ml
192
+ $sqlQuery = "DELETE FROM $wpdb->pmpro_membership_levels WHERE id = '$ml_id' LIMIT 1";
193
+ $r3 = $wpdb->query($sqlQuery);
194
+
195
+ if($r1 !== FALSE && $r2 !== FALSE && $r3 !== FALSE)
196
+ {
197
+ $msg = 3;
198
+ $msgt = __("Membership level deleted successfully.", "pmpro");
199
+ }
200
+ else
201
+ {
202
+ $msg = -3;
203
+ $msgt = __("Error deleting membership level.", "pmpro");
204
+ }
205
+ }
206
+ else
207
+ {
208
+ $msg = -3;
209
+ $msgt = __("Error deleting membership level.", "pmpro");
210
+ }
211
+ }
212
+
213
+ require_once(dirname(__FILE__) . "/admin_header.php");
214
+ ?>
215
+
216
+ <?php
217
+ if($edit)
218
+ {
219
+ ?>
220
+
221
+ <h2>
222
+ <?php
223
+ if($edit > 0)
224
+ echo __("Edit Membership Level", "pmpro");
225
+ else
226
+ echo __("Add New Membership Level", "pmpro");
227
+ ?>
228
+ </h2>
229
+
230
+ <div>
231
+ <?php
232
+ // get the level...
233
+ if(!empty($edit) && $edit > 0)
234
+ {
235
+ $level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '$edit' LIMIT 1", OBJECT);
236
+ $temp_id = $level->id;
237
+ }
238
+ elseif(!empty($copy) && $copy > 0)
239
+ {
240
+ $level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '$copy' LIMIT 1", OBJECT);
241
+ $temp_id = $level->id;
242
+ $level->id = NULL;
243
+ }
244
+ else
245
+
246
+ // didn't find a membership level, let's add a new one...
247
+ if(empty($level))
248
+ {
249
+ $level = new stdClass();
250
+ $level->id = NULL;
251
+ $level->name = NULL;
252
+ $level->description = NULL;
253
+ $level->confirmation = NULL;
254
+ $level->billing_amount = NULL;
255
+ $level->trial_amount = NULL;
256
+ $level->initial_payment = NULL;
257
+ $level->billing_limit = NULL;
258
+ $level->trial_limit = NULL;
259
+ $level->expiration_number = NULL;
260
+ $level->expiration_period = NULL;
261
+ $edit = -1;
262
+ }
263
+
264
+ //defaults for new levels
265
+ if(empty($copy) && $edit == -1)
266
+ {
267
+ $level->cycle_number = 1;
268
+ $level->cycle_period = "Month";
269
+ }
270
+
271
+ // grab the categories for the given level...
272
+ if(!empty($temp_id))
273
+ $level->categories = $wpdb->get_col("SELECT c.category_id
274
+ FROM $wpdb->pmpro_memberships_categories c
275
+ WHERE c.membership_id = '" . $temp_id . "'");
276
+ if(empty($level->categories))
277
+ $level->categories = array();
278
+
279
+ ?>
280
+ <form action="" method="post" enctype="multipart/form-data">
281
+ <input name="saveid" type="hidden" value="<?php echo $edit?>" />
282
+ <input type="hidden" name="action" value="save_membershiplevel" />
283
+ <table class="form-table">
284
+ <tbody>
285
+ <tr>
286
+ <th scope="row" valign="top"><label><?php _e('ID', 'pmpro');?>:</label></th>
287
+ <td>
288
+ <?php echo $level->id?>
289
+ </td>
290
+ </tr>
291
+
292
+ <tr>
293
+ <th scope="row" valign="top"><label for="name"><?php _e('Name', 'pmpro');?>:</label></th>
294
+ <td><input name="name" type="text" size="50" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->name))?>" /></td>
295
+ </tr>
296
+
297
+ <tr>
298
+ <th scope="row" valign="top"><label for="description"><?php _e('Description', 'pmpro');?>:</label></th>
299
+ <td>
300
+ <div id="poststuff" class="pmpro_description">
301
+ <?php
302
+ if(version_compare($wp_version, "3.3") >= 0)
303
+ wp_editor(stripslashes($level->description), "description", array("textarea_rows"=>5));
304
+ else
305
+ {
306
+ ?>
307
+ <textarea rows="10" cols="80" name="description" id="description"><?php echo stripslashes($level->description)?></textarea>
308
+ <?php
309
+ }
310
+ ?>
311
+ </div>
312
+ </td>
313
+ </tr>
314
+
315
+ <tr>
316
+ <th scope="row" valign="top"><label for="confirmation"><?php _e('Confirmation Message', 'pmpro');?>:</label></th>
317
+ <td>
318
+ <div class="pmpro_confirmation">
319
+ <?php
320
+ if(version_compare($wp_version, "3.3") >= 0)
321
+ wp_editor(stripslashes($level->confirmation), "confirmation", array("textarea_rows"=>5));
322
+ else
323
+ {
324
+ ?>
325
+ <textarea rows="10" cols="80" name="confirmation" id="confirmation"><?php echo stripslashes($level->confirmation)?></textarea>
326
+ <?php
327
+ }
328
+ ?>
329
+ </div>
330
+ </td>
331
+ </tr>
332
+ </tbody>
333
+ </table>
334
+
335
+ <h3 class="topborder"><?php _e('Billing Details', 'pmpro');?></h3>
336
+ <table class="form-table">
337
+ <tbody>
338
+ <tr>
339
+ <th scope="row" valign="top"><label for="initial_payment"><?php _e('Initial Payment', 'pmpro');?>:</label></th>
340
+ <td>
341
+ <?php
342
+ if(pmpro_getCurrencyPosition() == "left")
343
+ echo $pmpro_currency_symbol;
344
+ ?>
345
+ <input name="initial_payment" type="text" size="20" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->initial_payment))?>" />
346
+ <?php
347
+ if(pmpro_getCurrencyPosition() == "right")
348
+ echo $pmpro_currency_symbol;
349
+ ?>
350
+ <small><?php _e('The initial amount collected at registration.', 'pmpro');?></small></td>
351
+ </tr>
352
+
353
+ <tr>
354
+ <th scope="row" valign="top"><label><?php _e('Recurring Subscription', 'pmpro');?>:</label></th>
355
+ <td><input id="recurring" name="recurring" type="checkbox" value="yes" <?php if(pmpro_isLevelRecurring($level)) { echo "checked='checked'"; } ?> onclick="if(jQuery('#recurring').is(':checked')) { jQuery('.recurring_info').show(); if(jQuery('#custom_trial').is(':checked')) {jQuery('.trial_info').show();} else {jQuery('.trial_info').hide();} } else { jQuery('.recurring_info').hide();}" /> <small><?php _e('Check if this level has a recurring subscription payment.', 'pmpro');?></small></td>
356
+ </tr>
357
+
358
+ <tr class="recurring_info" <?php if(!pmpro_isLevelRecurring($level)) {?>style="display: none;"<?php } ?>>
359
+ <th scope="row" valign="top"><label for="billing_amount"><?php _e('Billing Amount', 'pmpro');?>:</label></th>
360
+ <td>
361
+ <?php
362
+ if(pmpro_getCurrencyPosition() == "left")
363
+ echo $pmpro_currency_symbol;
364
+ ?>
365
+ <input name="billing_amount" type="text" size="20" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->billing_amount))?>" />
366
+ <?php
367
+ if(pmpro_getCurrencyPosition() == "right")
368
+ echo $pmpro_currency_symbol;
369
+ ?>
370
+ <small><?php _e('per', 'pmpro');?></small>
371
+ <input id="cycle_number" name="cycle_number" type="text" size="10" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->cycle_number))?>" />
372
+ <select id="cycle_period" name="cycle_period">
373
+ <?php
374
+ $cycles = array( __('Day(s)', 'pmpro') => 'Day', __('Week(s)', 'pmpro') => 'Week', __('Month(s)', 'pmpro') => 'Month', __('Year(s)', 'pmpro') => 'Year' );
375
+ foreach ( $cycles as $name => $value ) {
376
+ echo "<option value='$value'";
377
+ if ( $level->cycle_period == $value ) echo " selected='selected'";
378
+ echo ">$name</option>";
379
+ }
380
+ ?>
381
+ </select>
382
+ <br /><small>
383
+ <?php _e('The amount to be billed one cycle after the initial payment.', 'pmpro');?>
384
+ <?php if($gateway == "stripe") { ?>
385
+ <br /><strong <?php if(!empty($pmpro_stripe_error)) { ?>class="pmpro_red"<?php } ?>><?php _e('Stripe integration currently only supports billing periods of "Week", "Month" or "Year".', 'pmpro');?>
386
+ <?php } elseif($gateway == "braintree") { ?>
387
+ <br /><strong <?php if(!empty($pmpro_braintree_error)) { ?>class="pmpro_red"<?php } ?>><?php _e('Braintree integration currently only supports billing periods of "Month" or "Year".', 'pmpro');?>
388
+ <?php } elseif($gateway == "payflowpro") { ?>
389
+ <br /><strong <?php if(!empty($pmpro_payflow_error)) { ?>class="pmpro_red"<?php } ?>><?php _e('Payflow integration currently only supports billing frequencies of 1 and billing periods of "Week", "Month" or "Year".', 'pmpro');?>
390
+ <?php } ?>
391
+ </small>
392
+ <?php if($gateway == "braintree" && $edit < 0) { ?>
393
+ <p class="pmpro_message"><strong><?php _e('Note', 'pmpro');?>:</strong> <?php _e('After saving this level, make note of the ID and create a "Plan" in your Braintree dashboard with the same settings and the "Plan ID" set to <em>pmpro_#</em>, where # is the level ID.', 'pmpro');?></p>
394
+ <?php } elseif($gateway == "braintree") { ?>
395
+ <p class="pmpro_message"><strong><?php _e('Note', 'pmpro');?>:</strong> <?php _e('You will need to create a "Plan" in your Braintree dashboard with the same settings and the "Plan ID" set to', 'pmpro');?> <em>pmpro_<?php echo $level->id;?></em>.</p>
396
+ <?php } ?>
397
+ </td>
398
+ </tr>
399
+
400
+ <tr class="recurring_info" <?php if(!pmpro_isLevelRecurring($level)) {?>style="display: none;"<?php } ?>>
401
+ <th scope="row" valign="top"><label for="billing_limit"><?php _e('Billing Cycle Limit', 'pmpro');?>:</label></th>
402
+ <td>
403
+ <input name="billing_limit" type="text" size="20" value="<?php echo $level->billing_limit?>" />
404
+ <br /><small>
405
+ <?php _e('The <strong>total</strong> number of recurring billing cycles for this level, including the trial period (if applicable) but not including the initial payment. Set to zero if membership is indefinite.', 'pmpro');?>
406
+ <?php if($gateway == "stripe") { ?>
407
+ <br /><strong <?php if(!empty($pmpro_stripe_error)) { ?>class="pmpro_red"<?php } ?>><?php _e('Stripe integration currently does not support billing limits. You can still set an expiration date below.', 'pmpro');?></strong>
408
+ <?php } ?>
409
+ </small>
410
+ </td>
411
+ </tr>
412
+
413
+ <tr class="recurring_info" <?php if (!pmpro_isLevelRecurring($level)) echo "style='display:none;'";?>>
414
+ <th scope="row" valign="top"><label><?php _e('Custom Trial', 'pmpro');?>:</label></th>
415
+ <td>
416
+ <input id="custom_trial" name="custom_trial" type="checkbox" value="yes" <?php if ( pmpro_isLevelTrial($level) ) { echo "checked='checked'"; } ?> onclick="jQuery('.trial_info').toggle();" /> <?php _e('Check to add a custom trial period.', 'pmpro');?>
417
+
418
+ <?php if($gateway == "twocheckout") { ?>
419
+ <br /><small><strong <?php if(!empty($pmpro_twocheckout_error)) { ?>class="pmpro_red"<?php } ?>><?php _e('2Checkout integration does not support custom trials. You can do one period trials by setting an initial payment different from the billing amount.', 'pmpro');?></strong></small>
420
+ <?php } ?>
421
+ </td>
422
+ </tr>
423
+
424
+ <tr class="trial_info recurring_info" <?php if (!pmpro_isLevelTrial($level)) echo "style='display:none;'";?>>
425
+ <th scope="row" valign="top"><label for="trial_amount"><?php _e('Trial Billing Amount', 'pmpro');?>:</label></th>
426
+ <td>
427
+ <?php
428
+ if(pmpro_getCurrencyPosition() == "left")
429
+ echo $pmpro_currency_symbol;
430
+ ?>
431
+ <input name="trial_amount" type="text" size="20" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->trial_amount))?>" />
432
+ <?php
433
+ if(pmpro_getCurrencyPosition() == "right")
434
+ echo $pmpro_currency_symbol;
435
+ ?>
436
+ <small><?php _e('for the first', 'pmpro');?></small>
437
+ <input name="trial_limit" type="text" size="10" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->trial_limit))?>" />
438
+ <small><?php _e('subscription payments', 'pmpro');?>.</small>
439
+ <?php if($gateway == "stripe") { ?>
440
+ <br /><small>
441
+ <strong <?php if(!empty($pmpro_stripe_error)) { ?>class="pmpro_red"<?php } ?>><?php _e('Stripe integration currently does not support trial amounts greater than $0.', 'pmpro');?></strong>
442
+ </small>
443
+ <?php } elseif($gateway == "braintree") { ?>
444
+ <br /><small>
445
+ <strong <?php if(!empty($pmpro_braintree_error)) { ?>class="pmpro_red"<?php } ?>><?php _e('Braintree integration currently does not support trial amounts greater than $0.', 'pmpro');?></strong>
446
+ </small>
447
+ <?php } elseif($gateway == "payflowpro") { ?>
448
+ <br /><small>
449
+ <strong <?php if(!empty($pmpro_payflow_error)) { ?>class="pmpro_red"<?php } ?>><?php _e('Payflow integration currently does not support trial amounts greater than $0.', 'pmpro');?></strong>
450
+ </small>
451
+ <?php } ?>
452
+ </td>
453
+ </tr>
454
+
455
+ </tbody>
456
+ </table>
457
+ <h3 class="topborder"><?php _e('Other Settings', 'pmpro');?></h3>
458
+ <table class="form-table">
459
+ <tbody>
460
+ <tr>
461
+ <th scope="row" valign="top"><label><?php _e('Disable New Signups', 'pmpro');?>:</label></th>
462
+ <td><input name="disable_signups" type="checkbox" value="yes" <?php if($level->id && !$level->allow_signups) { ?>checked="checked"<?php } ?> /> <?php _e('Check to hide this level from the membership levels page and disable registration.', 'pmpro');?></td>
463
+ </tr>
464
+
465
+ <tr>
466
+ <th scope="row" valign="top"><label><?php _e('Membership Expiration', 'pmpro');?>:</label></th>
467
+ <td><input id="expiration" name="expiration" type="checkbox" value="yes" <?php if(pmpro_isLevelExpiring($level)) { echo "checked='checked'"; } ?> onclick="if(jQuery('#expiration').is(':checked')) { jQuery('.expiration_info').show(); } else { jQuery('.expiration_info').hide();}" /> <?php _e('Check this to set when membership access expires.', 'pmpro');?></td>
468
+ </tr>
469
+
470
+ <tr class="expiration_info" <?php if(!pmpro_isLevelExpiring($level)) {?>style="display: none;"<?php } ?>>
471
+ <th scope="row" valign="top"><label for="billing_amount"><?php _e('Expires In', 'pmpro');?>:</label></th>
472
+ <td>
473
+ <input id="expiration_number" name="expiration_number" type="text" size="10" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->expiration_number))?>" />
474
+ <select id="expiration_period" name="expiration_period">
475
+ <?php
476
+ $cycles = array( __('Day(s)', 'pmpro') => 'Day', __('Week(s)', 'pmpro') => 'Week', __('Month(s)', 'pmpro') => 'Month', __('Year(s)', 'pmpro') => 'Year' );
477
+ foreach ( $cycles as $name => $value ) {
478
+ echo "<option value='$value'";
479
+ if ( $level->expiration_period == $value ) echo " selected='selected'";
480
+ echo ">$name</option>";
481
+ }
482
+ ?>
483
+ </select>
484
+ <br /><small><?php _e('Set the duration of membership access. Note that the any future payments (recurring subscription, if any) will be cancelled when the membership expires.', 'pmpro');?></small>
485
+ </td>
486
+ </tr>
487
+ </tbody>
488
+ </table>
489
+
490
+ <?php do_action("pmpro_membership_level_after_other_settings"); ?>
491
+
492
+ <h3 class="topborder"><?php _e('Content Settings', 'pmpro');?></h3>
493
+ <table class="form-table">
494
+ <tbody>
495
+ <tr>
496
+ <th scope="row" valign="top"><label><?php _e('Categories', 'pmpro');?>:</label></th>
497
+ <td>
498
+ <?php
499
+ $categories = get_categories( array( 'hide_empty' => 0 ) );
500
+ echo "<ul>";
501
+ foreach ( $categories as $cat )
502
+ {
503
+ $checked = in_array( $cat->term_id, $level->categories ) ? "checked='checked'" : '';
504
+ echo "<li><input name='membershipcategory_{$cat->term_id}' type='checkbox' value='yes' $checked /> {$cat->name}</li>\n";
505
+ }
506
+ echo "</ul>";
507
+ ?>
508
+ </td>
509
+ </tr>
510
+ </tbody>
511
+ </table>
512
+ <p class="submit topborder">
513
+ <input name="save" type="submit" class="button-primary" value="Save Level" />
514
+ <input name="cancel" type="button" value="Cancel" onclick="location.href='<?php echo get_admin_url(NULL, '/admin.php?page=pmpro-membershiplevels')?>';" />
515
+ </p>
516
+ </form>
517
+ </div>
518
+
519
+ <?php
520
+ }
521
+ else
522
+ {
523
+ ?>
524
+
525
+ <h2><?php _e('Membership Levels', 'pmpro');?> <a href="admin.php?page=pmpro-membershiplevels&edit=-1" class="add-new-h2"><?php _e('Add New Level', 'pmpro');?></a></h2>
526
+ <form id="posts-filter" method="get" action="">
527
+ <p class="search-box">
528
+ <label class="screen-reader-text" for="post-search-input"><?php _e('Search Levels', 'pmpro');?>:</label>
529
+ <input type="hidden" name="page" value="pmpro-membershiplevels" />
530
+ <input id="post-search-input" type="text" value="<?php echo $s?>" name="s" size="30" />
531
+ <input class="button" type="submit" value="<?php _e('Search Levels', 'pmpro');?>" id="search-submit" />
532
+ </p>
533
+ </form>
534
+
535
+ <br class="clear" />
536
+
537
+ <table class="widefat">
538
+ <thead>
539
+ <tr>
540
+ <th><?php _e('ID', 'pmpro');?></th>
541
+ <th><?php _e('Name', 'pmpro');?></th>
542
+ <th><?php _e('Initial Payment', 'pmpro');?></th>
543
+ <th><?php _e('Billing Cycle', 'pmpro');?></th>
544
+ <th><?php _e('Trial Cycle', 'pmpro');?></th>
545
+ <th><?php _e('Expiration', 'pmpro');?></th>
546
+ <th><?php _e('Allow Signups', 'pmpro');?></th>
547
+ <th></th>
548
+ <th></th>
549
+ <th></th>
550
+ </tr>
551
+ </thead>
552
+ <tbody>
553
+ <?php
554
+ $sqlQuery = "SELECT * FROM $wpdb->pmpro_membership_levels ";
555
+ if($s)
556
+ $sqlQuery .= "WHERE name LIKE '%$s%' ";
557
+ $sqlQuery .= "ORDER BY id ASC";
558
+
559
+ $levels = $wpdb->get_results($sqlQuery, OBJECT);
560
+
561
+ foreach($levels as $level)
562
+ {
563
+ ?>
564
+ <tr class="<?php if(!$level->allow_signups) { ?>pmpro_gray<?php } ?> <?php if(!pmpro_checkLevelForStripeCompatibility($level) || !pmpro_checkLevelForBraintreeCompatibility($level) || !pmpro_checkLevelForPayflowCompatibility($level) || !pmpro_checkLevelForTwoCheckoutCompatibility($level)) { ?>pmpro_error<?php } ?>">
565
+ <td><?php echo $level->id?></td>
566
+ <td><?php echo $level->name?></td>
567
+ <td>
568
+ <?php if(pmpro_isLevelFree($level)) { ?>
569
+ <?php _e('FREE', 'pmpro');?>
570
+ <?php } else { ?>
571
+ <?php echo pmpro_formatPrice($level->initial_payment);?>
572
+ <?php } ?>
573
+ </td>
574
+ <td>
575
+ <?php if(!pmpro_isLevelRecurring($level)) { ?>
576
+ --
577
+ <?php } else { ?>
578
+ <?php echo pmpro_formatPrice($level->billing_amount);?> <?php _e('every', 'pmpro');?> <?php echo $level->cycle_number.' '.pmpro_translate_billing_period($level->cycle_period,$level->cycle_number)?>
579
+
580
+ <?php if($level->billing_limit) { ?>(<?php _e('for', 'pmpro');?> <?php echo $level->billing_limit?> <?php echo sornot($level->cycle_period,$level->billing_limit)?>)<?php } ?>
581
+
582
+ <?php } ?>
583
+ </td>
584
+ <td>
585
+ <?php if(!pmpro_isLevelTrial($level)) { ?>
586
+ --
587
+ <?php } else { ?>
588
+ <?php echo pmpro_formatPrice($level->trial_amount);?> <?php _e('for', 'pmpro');?> <?php echo $level->trial_limit?> <?php echo sornot("payment",$level->trial_limit)?>
589
+ <?php } ?>
590
+ </td>
591
+ <td>
592
+ <?php if(!pmpro_isLevelExpiring($level)) { ?>
593
+ --
594
+ <?php } else { ?>
595
+ <?php _e('After', 'pmpro');?> <?php echo $level->expiration_number?> <?php echo sornot($level->expiration_period,$level->expiration_number)?>
596
+ <?php } ?>
597
+ </td>
598
+ <td><?php if($level->allow_signups) { ?><?php _e('Yes', 'pmpro');?><?php } else { ?><?php _e('No', 'pmpro');?><?php } ?></td>
599
+ <td align="center"><a href="admin.php?page=pmpro-membershiplevels&amp;edit=<?php echo $level->id?>" class="edit"><?php _e('edit', 'pmpro');?></a></td>
600
+ <td align="center"><a href="admin.php?page=pmpro-membershiplevels&amp;copy=<?php echo $level->id?>&amp;edit=-1" class="edit"><?php _e('copy', 'pmpro');?></a></td>
601
+ <td align="center"><a href="javascript: askfirst('<?php printf(__("Are you sure you want to delete membership level %s? All subscriptions will be cancelled.", "pmpro"), $level->name);?>','admin.php?page=pmpro-membershiplevels&amp;action=delete_membership_level&amp;deleteid=<?php echo $level->id?>'); void(0);" class="delete"><?php _e('delete', 'pmpro');?></a></td>
602
+ </tr>
603
+ <?php
604
+ }
605
+ ?>
606
+ </tbody>
607
+ </table>
608
+ <?php
609
+ }
610
+ ?>
611
+
612
+ <?php
613
+ require_once(dirname(__FILE__) . "/admin_footer.php");
614
+ ?>
615
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
adminpages/memberslist-csv.php CHANGED
@@ -1,86 +1,243 @@
1
- <?php
2
- //this file is launched via AJAX to get various data from the DB for the stranger_products plugin
3
-
4
- //wp includes
5
- define('WP_USE_THEMES', false);
6
- require('../../../../wp-load.php');
7
-
8
- //only admins can get this (PATCH!)
9
- if(!function_exists("current_user_can") || !current_user_can("manage_options"))
10
  {
11
- die("You do not have permissions to perform this action.");
12
  }
13
 
 
 
14
  //get users
15
- $s = $_REQUEST['s'];
16
- $l = $_REQUEST['l'];
 
 
 
 
 
 
 
17
 
18
  //some vars for the search
19
- $pn = $_REQUEST['pn'];
20
- if(!$pn) $pn = 1;
21
- $limit = $_REQUEST['limit'];
22
- if(!$limit) $limit = 15;
23
- $end = $pn * $limit;
24
- $start = $end - $limit;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
  if($s)
27
  {
28
- $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, mu.membership_id, mu.billing_amount, mu.cycle_period, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id WHERE mu.membership_id > 0 AND (u.user_login LIKE '%$s%' OR u.user_email LIKE '%$s%' OR um.meta_value LIKE '%$s%') ";
 
 
 
 
 
29
 
30
- if($l)
31
- $sqlQuery .= " AND mu.membership_id = '" . $l . "' ";
 
 
 
 
32
 
33
- $sqlQuery .= "GROUP BY u.ID ORDER BY user_registered DESC LIMIT $start, $limit";
 
 
 
 
 
 
 
 
34
  }
35
  else
36
  {
37
- $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, mu.membership_id, mu.billing_amount, mu.cycle_period, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id ";
38
- $sqlQuery .= "WHERE mu.membership_id > 0 ";
39
- if($l)
40
- $sqlQuery .= " AND mu.membership_id = '" . $l . "' ";
41
- $sqlQuery .= "ORDER BY user_registered DESC LIMIT $start, $limit";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  }
 
 
 
 
 
 
43
 
44
- $theusers = $wpdb->get_results($sqlQuery);
45
- $csvoutput = "id,username,firstname,lastname,email,membership,fee,term,joined\n";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
  if($theusers)
48
  {
49
- foreach($theusers as $theuser)
50
  {
 
51
  //get meta
52
- $sqlQuery = "SELECT meta_key as `key`, meta_value as `value` FROM $wpdb->usermeta WHERE $wpdb->usermeta.user_id = '" . $theuser->ID . "'";
 
 
 
 
 
 
53
  $metavalues = pmpro_getMetavalues($sqlQuery);
54
-
55
- $csvoutput .= enclose($theuser->ID) . "," .
56
- enclose($theuser->user_login) . "," .
57
- enclose($metavalues->first_name) . "," .
58
- enclose($metavalues->last_name) . "," .
59
- enclose($theuser->user_email) . "," .
60
- enclose($theuser->membership) . "," .
61
- enclose($theuser->billing_amount) . "," .
62
- enclose($theuser->cycle_period) . "," .
63
- enclose(date("m/d/Y", $theuser->joindate)) . "\n";
64
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  }
66
  }
67
-
68
- $size_in_bytes = strlen($csvoutput);
69
- header("Content-type: text/csv");
70
- //header("Content-type: application/vnd.ms-excel");
71
- if($s && $l)
72
- header("Content-Disposition: attachment; filename=members_list_" . $l . "_level" . $s . ".csv; size=$size_in_bytes");
73
- elseif($s)
74
- header("Content-Disposition: attachment; filename=members_list_" . $s . ".csv; size=$size_in_bytes");
75
- elseif($l)
76
- header("Content-Disposition: attachment; filename=members_list_level" . $l . ".csv; size=$size_in_bytes");
77
- else
78
- header("Content-Disposition: attachment; filename=members_list.csv; size=$size_in_bytes");
79
-
80
  print $csvoutput;
81
 
82
- function enclose($s)
83
  {
84
  return "\"" . str_replace("\"", "\\\"", $s) . "\"";
85
- }
86
- ?>
1
+ <?php
2
+ //only admins can get this
3
+ if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_memberslist_csv")))
 
 
 
 
 
 
4
  {
5
+ die(__("You do not have permissions to perform this action.", "pmpro"));
6
  }
7
 
8
+ global $wpdb;
9
+
10
  //get users
11
+ if(isset($_REQUEST['s']))
12
+ $s = $_REQUEST['s'];
13
+ else
14
+ $s = "";
15
+
16
+ if(isset($_REQUEST['l']))
17
+ $l = $_REQUEST['l'];
18
+ else
19
+ $l = false;
20
 
21
  //some vars for the search
22
+ if(!empty($_REQUEST['pn']))
23
+ $pn = $_REQUEST['pn'];
24
+ else
25
+ $pn = 1;
26
+
27
+ if(!empty($_REQUEST['limit']))
28
+ $limit = $_REQUEST['limit'];
29
+ else
30
+ $limit = false;
31
+
32
+ if($limit)
33
+ {
34
+ $end = $pn * $limit;
35
+ $start = $end - $limit;
36
+ }
37
+ else
38
+ {
39
+ $end = NULL;
40
+ $start = NULL;
41
+ }
42
 
43
  if($s)
44
  {
45
+ $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, u.user_login, u.user_nicename, u.user_url, u.user_registered, u.user_status, u.display_name, mu.membership_id, mu.initial_payment, mu.billing_amount, mu.cycle_period, UNIX_TIMESTAMP(mu.enddate) as enddate, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id ";
46
+
47
+ if($l == "oldmembers")
48
+ $sqlQuery .= " LEFT JOIN $wpdb->pmpro_memberships_users mu2 ON u.ID = mu2.user_id AND mu2.status = 'active' ";
49
+
50
+ $sqlQuery .= " WHERE mu.membership_id > 0 AND (u.user_login LIKE '%" . esc_sql($s) . "%' OR u.user_email LIKE '%" . esc_sql($s) . "%' OR um.meta_value LIKE '%" . esc_sql($s) . "%') ";
51
 
52
+ if($l == "oldmembers")
53
+ $sqlQuery .= " AND mu.status = 'inactive' AND mu2.status IS NULL ";
54
+ elseif($l)
55
+ $sqlQuery .= " AND mu.status = 'active' AND mu.membership_id = '" . esc_sql($l) . "' ";
56
+ else
57
+ $sqlQuery .= " AND mu.status = 'active' ";
58
 
59
+ $sqlQuery .= "GROUP BY u.ID ";
60
+
61
+ if($l == "oldmembers")
62
+ $sqlQuery .= "ORDER BY enddate DESC ";
63
+ else
64
+ $sqlQuery .= "ORDER BY u.user_registered DESC ";
65
+
66
+ if($limit)
67
+ $sqlQuery .= "LIMIT $start, $limit";
68
  }
69
  else
70
  {
71
+ $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS u.ID, UNIX_TIMESTAMP(mu.enddate) as enddate FROM $wpdb->users u LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id ";
72
+
73
+ if($l == "oldmembers")
74
+ $sqlQuery .= " LEFT JOIN $wpdb->pmpro_memberships_users mu2 ON u.ID = mu2.user_id AND mu2.status = 'active' ";
75
+
76
+ $sqlQuery .= " WHERE mu.membership_id > 0 ";
77
+
78
+ if($l == "oldmembers")
79
+ $sqlQuery .= " AND mu.status = 'inactive' AND mu2.status IS NULL ";
80
+ elseif($l)
81
+ $sqlQuery .= " AND mu.status = 'active' AND mu.membership_id = '" . $l . "' ";
82
+ else
83
+ $sqlQuery .= " AND mu.status = 'active' ";
84
+
85
+ $sqlQuery .= "GROUP BY u.ID ";
86
+
87
+ if($l == "oldmembers")
88
+ $sqlQuery .= "ORDER BY enddate DESC ";
89
+ else
90
+ $sqlQuery .= "ORDER BY u.user_registered DESC ";
91
+
92
+ if($limit)
93
+ $sqlQuery .= "LIMIT $start, $limit";
94
  }
95
+
96
+ //filter
97
+ $sqlQuery = apply_filters("pmpro_members_list_sql", $sqlQuery);
98
+
99
+ //get users
100
+ $theusers = $wpdb->get_col($sqlQuery);
101
 
102
+ //begin output
103
+ header("Content-type: text/csv");
104
+ if($s && $l == "oldmembers")
105
+ header("Content-Disposition: attachment; filename=members_list_expired_" . sanitize_file_name($s) . ".csv");
106
+ elseif($s && $l)
107
+ header("Content-Disposition: attachment; filename=members_list_" . intval($l) . "_level_" . sanitize_file_name($s) . ".csv");
108
+ elseif($s)
109
+ header("Content-Disposition: attachment; filename=members_list_" . sanitize_file_name($s) . ".csv");
110
+ elseif($l == "oldmembers")
111
+ header("Content-Disposition: attachment; filename=members_list_expired.csv");
112
+ else
113
+ header("Content-Disposition: attachment; filename=members_list.csv");
114
+
115
+ $heading = "id,username,firstname,lastname,email,billing firstname,billing lastname,address1,address2,city,state,zipcode,country,phone,membership,initial payment,fee,term,discount_code_id,discount_code,joined";
116
+
117
+ if($l == "oldmembers")
118
+ $heading .= ",ended";
119
+ else
120
+ $heading .= ",expires";
121
+
122
+ $heading = apply_filters("pmpro_members_list_csv_heading", $heading);
123
+ $csvoutput = $heading;
124
+
125
+ //these are the meta_keys for the fields (arrays are object, property. so e.g. $theuser->ID)
126
+ $default_columns = array(
127
+ array("theuser", "ID"),
128
+ array("theuser", "user_login"),
129
+ array("metavalues", "first_name"),
130
+ array("metavalues", "last_name"),
131
+ array("theuser", "user_email"),
132
+ array("metavalues", "pmpro_bfirstname"),
133
+ array("metavalues", "pmpro_blastname"),
134
+ array("metavalues", "pmpro_baddress1"),
135
+ array("metavalues", "pmpro_baddress2"),
136
+ array("metavalues", "pmpro_bcity"),
137
+ array("metavalues", "pmpro_bstate"),
138
+ array("metavalues", "pmpro_bzipcode"),
139
+ array("metavalues", "pmpro_bcountry"),
140
+ array("metavalues", "pmpro_bphone"),
141
+ array("theuser", "membership"),
142
+ array("theuser", "initial_payment"),
143
+ array("theuser", "billing_amount"),
144
+ array("theuser", "cycle_period"),
145
+ array("discount_code", "id"),
146
+ array("discount_code", "code")
147
+ //joindate and enddate are handled specifically below
148
+ );
149
+
150
+ //filter
151
+ $default_columns = apply_filters("pmpro_members_list_csv_default_columns", $default_columns);
152
+
153
+ //any extra columns
154
+ $extra_columns = apply_filters("pmpro_members_list_csv_extra_columns", array());
155
+ if(!empty($extra_columns))
156
+ {
157
+ foreach($extra_columns as $heading => $callback)
158
+ {
159
+ $csvoutput .= "," . $heading;
160
+ }
161
+ }
162
+
163
+ $csvoutput .= "\n";
164
+
165
+ //output
166
+ echo $csvoutput;
167
+ $csvoutput = "";
168
 
169
  if($theusers)
170
  {
171
+ foreach($theusers as $user_id)
172
  {
173
+ //MULTI: This query will need to be updated to support multiple levels per user. Should probably just dump multiple rows for each membership.
174
  //get meta
175
+
176
+ if($l == "oldmembers")
177
+ $theuser = $wpdb->get_row("SELECT u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, u.user_login, u.user_nicename, u.user_url, u.user_registered, u.user_status, u.display_name, mu.membership_id, mu.initial_payment, mu.billing_amount, mu.cycle_period, UNIX_TIMESTAMP(mu.enddate) as enddate, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id WHERE u.ID = '" . $user_id . "' ORDER BY mu.id DESC LIMIT 1");
178
+ else
179
+ $theuser = $wpdb->get_row("SELECT u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, u.user_login, u.user_nicename, u.user_url, u.user_registered, u.user_status, u.display_name, mu.membership_id, mu.initial_payment, mu.billing_amount, mu.cycle_period, UNIX_TIMESTAMP(mu.enddate) as enddate, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id AND mu.status = 'active' LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id WHERE u.ID = '" . $user_id . "' LIMIT 1");
180
+
181
+ $sqlQuery = "SELECT meta_key as `key`, meta_value as `value` FROM $wpdb->usermeta WHERE $wpdb->usermeta.user_id = '" . $user_id . "'";
182
  $metavalues = pmpro_getMetavalues($sqlQuery);
183
+ $theuser->metavalues = $metavalues;
184
+ $sqlQuery = "SELECT c.id, c.code FROM $wpdb->pmpro_discount_codes_uses cu LEFT JOIN $wpdb->pmpro_discount_codes c ON cu.code_id = c.id WHERE cu.user_id = '" . $theuser->ID . "' ORDER BY c.id DESC LIMIT 1";
185
+ $discount_code = $wpdb->get_row($sqlQuery);
186
+
187
+ //default columns
188
+ if(!empty($default_columns))
189
+ {
190
+ $count = 0;
191
+ foreach($default_columns as $col)
192
+ {
193
+ //add comma after the first item
194
+ $count++;
195
+ if($count > 1)
196
+ $csvoutput .= ",";
197
+
198
+ //checking $object->property. note the double $$
199
+ if(!empty($$col[0]->$col[1]))
200
+ $csvoutput .= pmpro_enclose($$col[0]->$col[1]); //output the value
201
+ }
202
+ }
203
+
204
+ //joindate and enddate
205
+ $csvoutput .= "," . pmpro_enclose(date("Y-m-d", $theuser->joindate)) . ",";
206
+
207
+ if($theuser->membership_id)
208
+ {
209
+ if($theuser->enddate)
210
+ $csvoutput .= pmpro_enclose(apply_filters("pmpro_memberslist_expires_column", date("Y-m-d", $theuser->enddate), $theuser));
211
+ else
212
+ $csvoutput .= pmpro_enclose(apply_filters("pmpro_memberslist_expires_column", "Never", $theuser));
213
+ }
214
+ elseif($l == "oldmembers" && $theuser->enddate)
215
+ {
216
+ $csvoutput .= pmpro_enclose(date("Y-m-d", $theuser->enddate));
217
+ }
218
+ else
219
+ $csvoutput .= "N/A";
220
+
221
+ //any extra columns
222
+ if(!empty($extra_columns))
223
+ {
224
+ foreach($extra_columns as $heading => $callback)
225
+ {
226
+ $csvoutput .= "," . pmpro_enclose(call_user_func($callback, $theuser, $heading));
227
+ }
228
+ }
229
+
230
+ $csvoutput .= "\n";
231
+
232
+ //output
233
+ echo $csvoutput;
234
+ $csvoutput = "";
235
  }
236
  }
237
+
 
 
 
 
 
 
 
 
 
 
 
 
238
  print $csvoutput;
239
 
240
+ function pmpro_enclose($s)
241
  {
242
  return "\"" . str_replace("\"", "\\\"", $s) . "\"";
243
+ }
 
adminpages/memberslist.php CHANGED
@@ -1,126 +1,238 @@
1
- <?php
2
- //vars
3
- global $wpdb;
4
- $s = $_REQUEST['s'];
5
- $l = $_REQUEST['l'];
6
- ?>
7
- <div class="wrap">
8
- <form id="posts-filter" method="get" action="">
9
- <div id="icon-users" class="icon32"><br /></div>
10
- <h2>
11
- Members Report
12
- <small>(<a target="_blank" href="<?=PMPRO_URL?>/adminpages/memberslist-csv.php?s=<?=$s?>&l=<?=$l?>">Export to CSV</a>)</small>
13
- </h2>
14
- <ul class="subsubsub">
15
- <li>
16
- Show <select name="l" onchange="jQuery('#posts-filter').submit();">
17
- <option value="" <?php if(!$l) { ?>selected="selected"<?php } ?>>All Levels</option>
18
- <?php
19
- $levels = $wpdb->get_results("SELECT id, name FROM $wpdb->pmpro_membership_levels ORDER BY name");
20
- foreach($levels as $level)
21
- {
22
- ?>
23
- <option value="<?=$level->id?>" <?php if($l == $level->id) { ?>selected="selected"<?php } ?>><?=$level->name?></option>
24
- <?php
25
- }
26
- ?>
27
- </select>
28
- </li>
29
- </ul>
30
- <p class="search-box">
31
- <label class="hidden" for="post-search-input">Search Members:</label>
32
- <input type="hidden" name="page" value="pmpro-memberslist" />
33
- <input id="post-search-input" type="text" value="<?=$s?>" name="s"/>
34
- <input class="button" type="submit" value="Search Members"/>
35
- </p>
36
- <table class="widefat">
37
- <thead>
38
- <tr class="thead">
39
- <th>ID</th>
40
- <th>Username</th>
41
- <th>First&nbsp;Name</th>
42
- <th>Last&nbsp;Name</th>
43
- <th>Email</th>
44
- <th>Membership</th>
45
- <th>Fee</th>
46
- <th>Joined</th>
47
- </tr>
48
- </thead>
49
- <tbody id="users" class="list:user user-list">
50
- <?php
51
- //some vars for the search
52
- $pn = $_REQUEST['pn'];
53
- if(!$pn) $pn = 1;
54
- $limit = $_REQUEST['limit'];
55
- if(!$limit) $limit = 15;
56
- $end = $pn * $limit;
57
- $start = $end - $limit;
58
-
59
- if($s)
60
- {
61
- $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, mu.membership_id, mu.billing_amount, mu.cycle_period, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id WHERE mu.membership_id > 0 AND (u.user_login LIKE '%$s%' OR u.user_email LIKE '%$s%' OR um.meta_value LIKE '%$s%') ";
62
-
63
- if($l)
64
- $sqlQuery .= " AND mu.membership_id = '" . $l . "' ";
65
-
66
- $sqlQuery .= "GROUP BY u.ID ORDER BY user_registered DESC LIMIT $start, $limit";
67
- }
68
- else
69
- {
70
- $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, mu.membership_id, mu.billing_amount, mu.cycle_period, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id ";
71
- $sqlQuery .= "WHERE mu.membership_id > 0 ";
72
- if($l)
73
- $sqlQuery .= " AND mu.membership_id = '" . $l . "' ";
74
- $sqlQuery .= "ORDER BY user_registered DESC LIMIT $start, $limit";
75
- }
76
-
77
- $theusers = $wpdb->get_results($sqlQuery);
78
- $totalrows = $wpdb->get_var("SELECT FOUND_ROWS() as found_rows");
79
- foreach($theusers as $theuser)
80
- {
81
- //get meta
82
- $sqlQuery = "SELECT meta_key as `key`, meta_value as `value` FROM $wpdb->usermeta WHERE $wpdb->usermeta.user_id = '" . $theuser->ID . "'";
83
- $metavalues = pmpro_getMetavalues($sqlQuery);
84
- ?>
85
- <tr <?php if($count++ % 2 == 0) { ?>class="alternate"<?php } ?>>
86
- <td><?=$theuser->ID?></td>
87
- <td>
88
- <?=get_avatar($theuser->ID, 32)?>
89
- <strong><a href="user-edit.php?user_id=<?=$theuser->ID?>"><?=$theuser->user_login?></a></strong>
90
- </td>
91
- <td><?=$metavalues->first_name?></td>
92
- <td><?=$metavalues->last_name?></td>
93
- <td><a href="mailto:<?=$theuser->user_email?>"><?=$theuser->user_email?></a></td>
94
- <td><?=$theuser->membership?></td>
95
- <td>
96
- <?php if($theuser->billing_amount > 0) { ?>
97
- $<?=$theuser->billing_amount?>/<?=$theuser->cycle_period?>
98
- <?php } else { ?>
99
- -
100
- <?php } ?>
101
- </td>
102
- <td><?=date("m/d/Y", $theuser->joindate)?></td>
103
- </tr>
104
- <?php
105
- }
106
-
107
- if(!$theusers)
108
- {
109
- ?>
110
- <tr>
111
- <td colspan="9"><p>No members found. <?php if($l) { ?><a href="?page=pmpro-memberslist&s=<?=$s?>">Search all levels</a>.<?php } ?></p></td>
112
- </tr>
113
- <?php
114
- }
115
- ?>
116
- </tbody>
117
- </table>
118
- </form>
119
-
120
- <?php
121
- echo pmpro_getPaginationString($pn, $totalrows, $limit, 1, "/wp-admin/admin.php?page=pmpro-memberslist&s=" . urlencode($s), "&l=$l&limit=$limit&pn=");
122
- ?>
123
-
124
- </div>
125
- <?php
126
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //only admins can get this
3
+ if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_memberslist")))
4
+ {
5
+ die(__("You do not have permissions to perform this action.", "pmpro"));
6
+ }
7
+
8
+ //vars
9
+ global $wpdb;
10
+ if(isset($_REQUEST['s']))
11
+ $s = $_REQUEST['s'];
12
+ else
13
+ $s = "";
14
+
15
+ if(isset($_REQUEST['l']))
16
+ $l = $_REQUEST['l'];
17
+ else
18
+ $l = false;
19
+
20
+ require_once(dirname(__FILE__) . "/admin_header.php");
21
+ ?>
22
+
23
+ <form id="posts-filter" method="get" action="">
24
+ <h2>
25
+ <?php _e('Members List', 'pmpro');?>
26
+ <a target="_blank" href="<?php echo admin_url('admin-ajax.php');?>?action=memberslist_csv&s=<?php echo $s?>&l=<?php echo $l?>" class="add-new-h2"><?php _e('Export to CSV', 'pmpro');?></a>
27
+ </h2>
28
+ <ul class="subsubsub">
29
+ <li>
30
+ <?php _e('Show', 'pmpro');?>
31
+ <select name="l" onchange="jQuery('#posts-filter').submit();">
32
+ <option value="" <?php if(!$l) { ?>selected="selected"<?php } ?>><?php _e('All Levels', 'pmpro');?></option>
33
+ <?php
34
+ $levels = $wpdb->get_results("SELECT id, name FROM $wpdb->pmpro_membership_levels ORDER BY name");
35
+ foreach($levels as $level)
36
+ {
37
+ ?>
38
+ <option value="<?php echo $level->id?>" <?php if($l == $level->id) { ?>selected="selected"<?php } ?>><?php echo $level->name?></option>
39
+ <?php
40
+ }
41
+ ?>
42
+ <option value="oldmembers" <?php if($l == "oldmembers") { ?>selected="selected"<?php } ?>><?php _e('Old Members', 'pmpro');?></option>
43
+ </select>
44
+ </li>
45
+ </ul>
46
+ <p class="search-box">
47
+ <label class="hidden" for="post-search-input"><?php _e('Search Members', 'pmpro');?>:</label>
48
+ <input type="hidden" name="page" value="pmpro-memberslist" />
49
+ <input id="post-search-input" type="text" value="<?php echo $s?>" name="s"/>
50
+ <input class="button" type="submit" value="<?php _e('Search Members', 'pmpro');?>"/>
51
+ </p>
52
+ <?php
53
+ //some vars for the search
54
+ if(isset($_REQUEST['pn']))
55
+ $pn = $_REQUEST['pn'];
56
+ else
57
+ $pn = 1;
58
+
59
+ if(isset($_REQUEST['limit']))
60
+ $limit = $_REQUEST['limit'];
61
+ else
62
+ $limit = 15;
63
+
64
+ $end = $pn * $limit;
65
+ $start = $end - $limit;
66
+
67
+ if($s)
68
+ {
69
+ $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, mu.membership_id, mu.initial_payment, mu.billing_amount, mu.cycle_period, mu.cycle_number, mu.billing_limit, mu.trial_amount, mu.trial_limit, UNIX_TIMESTAMP(mu.startdate) as startdate, UNIX_TIMESTAMP(mu.enddate) as enddate, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id ";
70
+
71
+ if($l == "oldmembers")
72
+ $sqlQuery .= " LEFT JOIN $wpdb->pmpro_memberships_users mu2 ON u.ID = mu2.user_id AND mu2.status = 'active' ";
73
+
74
+ $sqlQuery .= " WHERE mu.membership_id > 0 AND (u.user_login LIKE '%$s%' OR u.user_email LIKE '%$s%' OR um.meta_value LIKE '%$s%') ";
75
+
76
+ if($l == "oldmembers")
77
+ $sqlQuery .= " AND mu.status = 'inactive' AND mu2.status IS NULL ";
78
+ elseif($l)
79
+ $sqlQuery .= " AND mu.status = 'active' AND mu.membership_id = '" . $l . "' ";
80
+ else
81
+ $sqlQuery .= " AND mu.status = 'active' ";
82
+
83
+ $sqlQuery .= "GROUP BY u.ID ";
84
+
85
+ if($l == "oldmembers")
86
+ $sqlQuery .= "ORDER BY enddate DESC ";
87
+ else
88
+ $sqlQuery .= "ORDER BY u.user_registered DESC ";
89
+
90
+ $sqlQuery .= "LIMIT $start, $limit";
91
+ }
92
+ else
93
+ {
94
+ $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, mu.membership_id, mu.initial_payment, mu.billing_amount, mu.cycle_period, mu.cycle_number, mu.billing_limit, mu.trial_amount, mu.trial_limit, UNIX_TIMESTAMP(mu.startdate) as startdate, UNIX_TIMESTAMP(mu.enddate) as enddate, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id";
95
+
96
+ if($l == "oldmembers")
97
+ $sqlQuery .= " LEFT JOIN $wpdb->pmpro_memberships_users mu2 ON u.ID = mu2.user_id AND mu2.status = 'active' ";
98
+
99
+ $sqlQuery .= " WHERE mu.membership_id > 0 ";
100
+
101
+ if($l == "oldmembers")
102
+ $sqlQuery .= " AND mu.status = 'inactive' AND mu2.status IS NULL ";
103
+ elseif($l)
104
+ $sqlQuery .= " AND mu.status = 'active' AND mu.membership_id = '" . $l . "' ";
105
+ else
106
+ $sqlQuery .= " AND mu.status = 'active' ";
107
+ $sqlQuery .= "GROUP BY u.ID ";
108
+
109
+ if($l == "oldmembers")
110
+ $sqlQuery .= "ORDER BY enddate DESC ";
111
+ else
112
+ $sqlQuery .= "ORDER BY u.user_registered DESC ";
113
+
114
+ $sqlQuery .= "LIMIT $start, $limit";
115
+ }
116
+
117
+ $sqlQuery = apply_filters("pmpro_members_list_sql", $sqlQuery);
118
+
119
+ $theusers = $wpdb->get_results($sqlQuery);
120
+ $totalrows = $wpdb->get_var("SELECT FOUND_ROWS() as found_rows");
121
+
122
+ if($theusers)
123
+ {
124
+ $calculate_revenue = apply_filters("pmpro_memberslist_calculate_revenue", false);
125
+ if($calculate_revenue)
126
+ {
127
+ $initial_payments = pmpro_calculateInitialPaymentRevenue($s, $l);
128
+ $recurring_payments = pmpro_calculateRecurringRevenue($s, $l);
129
+ ?>
130
+ <p class="clear"><?php echo strval($totalrows)?> members found. These members have paid <strong>$<?php echo number_format($initial_payments)?> in initial payments</strong> and will generate an estimated <strong>$<?php echo number_format($recurring_payments)?> in revenue over the next year</strong>, or <strong>$<?php echo number_format($recurring_payments/12)?>/month</strong>. <span class="pmpro_lite">(This estimate does not take into account trial periods or billing limits.)</span></p>
131
+ <?php
132
+ }
133
+ else
134
+ {
135
+ ?>
136
+ <p class="clear"><?php printf(__("%d members found.", "pmpro"), $totalrows);?></span></p>
137
+ <?php
138
+ }
139
+ }
140
+ ?>
141
+ <table class="widefat">
142
+ <thead>
143
+ <tr class="thead">
144
+ <th><?php _e('ID', 'pmpro');?></th>
145
+ <th><?php _e('Username', 'pmpro');?></th>
146
+ <th><?php _e('First&nbsp;Name', 'pmpro');?></th>
147
+ <th><?php _e('Last&nbsp;Name', 'pmpro');?></th>
148
+ <th><?php _e('Email', 'pmpro');?></th>
149
+ <?php do_action("pmpro_memberslist_extra_cols_header", $theusers);?>
150
+ <th><?php _e('Billing Address', 'pmpro');?></th>
151
+ <th><?php _e('Membership', 'pmpro');?></th>
152
+ <th><?php _e('Fee', 'pmpro');?></th>
153
+ <th><?php _e('Joined', 'pmpro');?></th>
154
+ <th>
155
+ <?php
156
+ if($l == "oldmembers")
157
+ _e('Ended', 'pmpro');
158
+ else
159
+ _e('Expires', 'pmpro');
160
+ ?>
161
+ </th>
162
+ </tr>
163
+ </thead>
164
+ <tbody id="users" class="list:user user-list">
165
+ <?php
166
+ $count = 0;
167
+ foreach($theusers as $auser)
168
+ {
169
+ //get meta
170
+ $theuser = get_userdata($auser->ID);
171
+ ?>
172
+ <tr <?php if($count++ % 2 == 0) { ?>class="alternate"<?php } ?>>
173
+ <td><?php echo $theuser->ID?></td>
174
+ <td>
175
+ <?php echo get_avatar($theuser->ID, 32)?>
176
+ <strong>
177
+ <?php
178
+ $userlink = '<a href="user-edit.php?user_id=' . $theuser->ID . '">' . $theuser->user_login . '</a>';
179
+ $userlink = apply_filters("pmpro_members_list_user_link", $userlink, $theuser);
180
+ echo $userlink;
181
+ ?>
182
+ </strong>
183
+ </td>
184
+ <td><?php echo $theuser->first_name?></td>
185
+ <td><?php echo $theuser->last_name?></td>
186
+ <td><a href="mailto:<?php echo $theuser->user_email?>"><?php echo $theuser->user_email?></a></td>
187
+ <?php do_action("pmpro_memberslist_extra_cols_body", $theuser);?>
188
+ <td>
189
+ <?php
190
+ echo pmpro_formatAddress(trim($theuser->pmpro_bfirstname . " " . $theuser->pmpro_blastname), $theuser->pmpro_baddress1, $theuser->pmpro_baddress2, $theuser->pmpro_bcity, $theuser->pmpro_bstate, $theuser->pmpro_bzipcode, $theuser->pmpro_bcountry, $theuser->pmpro_bphone);
191
+ ?>
192
+ </td>
193
+ <td><?php echo $auser->membership?></td>
194
+ <td>
195
+ <?php if((float)$auser->initial_payment > 0) { ?>
196
+ <?php echo pmpro_formatPrice($auser->initial_payment);?>
197
+ <?php } ?>
198
+ <?php if((float)$auser->initial_payment > 0 && (float)$auser->billing_amount > 0) { ?>+<br /><?php } ?>
199
+ <?php if((float)$auser->billing_amount > 0) { ?>
200
+ <?php echo pmpro_formatPrice($auser->billing_amount);?>/<?php if($auser->cycle_number > 1) { echo $auser->cycle_number . " " . $auser->cycle_period . "s"; } else { echo $auser->cycle_period; } ?>
201
+ <?php } ?>
202
+ <?php if((float)$auser->initial_payment <= 0 && (float)$auser->billing_amount <= 0) { ?>
203
+ -
204
+ <?php } ?>
205
+ </td>
206
+ <td><?php echo date(get_option("date_format"), strtotime($theuser->user_registered, current_time("timestamp")))?></td>
207
+ <td>
208
+ <?php
209
+ if($auser->enddate)
210
+ echo apply_filters("pmpro_memberslist_expires_column", date(get_option('date_format'), $auser->enddate), $auser);
211
+ else
212
+ echo __(apply_filters("pmpro_memberslist_expires_column", "Never", $auser), "pmpro");
213
+ ?>
214
+ </td>
215
+ </tr>
216
+ <?php
217
+ }
218
+
219
+ if(!$theusers)
220
+ {
221
+ ?>
222
+ <tr>
223
+ <td colspan="9"><p><?php _e("No members found.", "pmpro");?> <?php if($l) { ?><a href="?page=pmpro-memberslist&s=<?php echo $s?>"><?php _e("Search all levels", "pmpro");?></a>.<?php } ?></p></td>
224
+ </tr>
225
+ <?php
226
+ }
227
+ ?>
228
+ </tbody>
229
+ </table>
230
+ </form>
231
+
232
+ <?php
233
+ echo pmpro_getPaginationString($pn, $totalrows, $limit, 1, get_admin_url(NULL, "/admin.php?page=pmpro-memberslist&s=" . urlencode($s)), "&l=$l&limit=$limit&pn=");
234
+ ?>
235
+
236
+ <?php
237
+ require_once(dirname(__FILE__) . "/admin_footer.php");
238
+ ?>
adminpages/orders-csv.php ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //only admins can get this
3
+ if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_orders_csv")))
4
+ {
5
+ die(__("You do not have permissions to perform this action.", "pmpro"));
6
+ }
7
+
8
+ global $wpdb;
9
+
10
+ //get users
11
+ if(isset($_REQUEST['s']))
12
+ $s = $_REQUEST['s'];
13
+ else
14
+ $s = "";
15
+
16
+ if(isset($_REQUEST['l']))
17
+ $l = $_REQUEST['l'];
18
+ else
19
+ $l = false;
20
+
21
+ if(isset($_REQUEST['start-month']))
22
+ $start_month = $_REQUEST['start-month'];
23
+ else
24
+ $start_month = "1";
25
+
26
+ if(isset($_REQUEST['start-day']))
27
+ $start_day = $_REQUEST['start-day'];
28
+ else
29
+ $start_day = "1";
30
+
31
+ if(isset($_REQUEST['start-year']))
32
+ $start_year = $_REQUEST['start-year'];
33
+ else
34
+ $start_year = date("Y");
35
+
36
+ if(isset($_REQUEST['end-month']))
37
+ $end_month = $_REQUEST['end-month'];
38
+ else
39
+ $end_month = date("n");
40
+
41
+ if(isset($_REQUEST['end-day']))
42
+ $end_day = $_REQUEST['end-day'];
43
+ else
44
+ $end_day = date("j");
45
+
46
+ if(isset($_REQUEST['end-year']))
47
+ $end_year = $_REQUEST['end-year'];
48
+ else
49
+ $end_year = date("Y");
50
+
51
+ if(isset($_REQUEST['predefined-date']))
52
+ $predefined_date = $_REQUEST['predefined-date'];
53
+ else
54
+ $predefined_date = "This Month";
55
+
56
+ if(isset($_REQUEST['status']))
57
+ $status = $_REQUEST['status'];
58
+ else
59
+ $status = "";
60
+
61
+ if(isset($_REQUEST['filter']))
62
+ $filter = sanitize_text_field($_REQUEST['filter']);
63
+ else
64
+ $filter = "all";
65
+
66
+ //some vars for the search
67
+ if(!empty($_REQUEST['pn']))
68
+ $pn = $_REQUEST['pn'];
69
+ else
70
+ $pn = 1;
71
+
72
+ if(!empty($_REQUEST['limit']))
73
+ $limit = $_REQUEST['limit'];
74
+ else
75
+ $limit = false;
76
+
77
+ if($limit)
78
+ {
79
+ $end = $pn * $limit;
80
+ $start = $end - $limit;
81
+ }
82
+ else
83
+ {
84
+ $end = NULL;
85
+ $start = NULL;
86
+ }
87
+
88
+ //filters
89
+ if($filter == "all" || !$filter)
90
+ $condition = "1=1";
91
+ elseif($filter == "within-a-date-range")
92
+ {
93
+ $start_date = $start_year."-".$start_month."-".$start_day;
94
+ $end_date = $end_year."-".$end_month."-".$end_day;
95
+
96
+ //add times to dates
97
+ $start_date = $start_date . " 00:00:00";
98
+ $end_date = $end_date . " 23:59:59";
99
+
100
+ $condition = "timestamp BETWEEN '".$start_date."' AND '".$end_date."'";
101
+ }
102
+ elseif($filter == "predefined-date-range")
103
+ {
104
+ if($predefined_date == "Last Month")
105
+ {
106
+ $start_date = date("Y-m-d", strtotime("first day of last month", current_time("timestamp")));
107
+ $end_date = date("Y-m-d", strtotime("last day of last month", current_time("timestamp")));
108
+ }
109
+ elseif($predefined_date == "This Month")
110
+ {
111
+ $start_date = date("Y-m-d", strtotime("first day of this month", current_time("timestamp")));
112
+ $end_date = date("Y-m-d", strtotime("last day of this month", current_time("timestamp")));
113
+ }
114
+ elseif($predefined_date == "This Year")
115
+ {
116
+ $year = date('Y');
117
+ $start_date = date("Y-m-d", strtotime("first day of January $year", current_time("timestamp")));
118
+ $end_date = date("Y-m-d", strtotime("last day of December $year", current_time("timestamp")));
119
+ }
120
+
121
+ elseif($predefined_date == "Last Year")
122
+ {
123
+ $year = date('Y') - 1;
124
+ $start_date = date("Y-m-d", strtotime("first day of January $year", current_time("timestamp")));
125
+ $end_date = date("Y-m-d", strtotime("last day of December $year", current_time("timestamp")));
126
+ }
127
+
128
+ //add times to dates
129
+ $start_date = $start_date . " 00:00:00";
130
+ $end_date = $end_date . " 23:59:59";
131
+
132
+ $condition = "timestamp BETWEEN '".$start_date."' AND '".$end_date."'";
133
+ }
134
+ elseif($filter == "within-a-level")
135
+ {
136
+ $condition = "membership_id = $l";
137
+ }
138
+ elseif($filter == "within-a-status")
139
+ {
140
+ $condition = "status = '$status' ";
141
+ }
142
+
143
+ //string search
144
+ if($s)
145
+ {
146
+ $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS o.id FROM $wpdb->pmpro_membership_orders o LEFT JOIN $wpdb->users u ON o.user_id = u.ID LEFT JOIN $wpdb->pmpro_membership_levels l ON o.membership_id = l.id ";
147
+
148
+ $join_with_usermeta = apply_filters("pmpro_orders_search_usermeta", false);
149
+ if($join_with_usermeta)
150
+ $sqlQuery .= "LEFT JOIN $wpdb->usermeta um ON o.user_id = um.user_id ";
151
+
152
+ $sqlQuery .= "WHERE (1=2 ";
153
+
154
+ $fields = array("o.id", "o.code", "o.billing_name", "o.billing_street", "o.billing_city", "o.billing_state", "o.billing_zip", "o.billing_phone", "o.payment_type", "o.cardtype", "o.accountnumber", "o.status", "o.gateway", "o.gateway_environment", "o.payment_transaction_id", "o.subscription_transaction_id", "u.user_login", "u.user_email", "u.display_name", "l.name");
155
+
156
+ if($join_with_usermeta)
157
+ $fields[] = "um.meta_value";
158
+
159
+ $fields = apply_filters("pmpro_orders_search_fields", $fields);
160
+
161
+ foreach($fields as $field)
162
+ $sqlQuery .= " OR " . $field . " LIKE '%" . esc_sql($s) . "%' ";
163
+ $sqlQuery .= ") ";
164
+
165
+ $sqlQuery .= "AND " . $condition . " ";
166
+
167
+ $sqlQuery .= "GROUP BY o.id ORDER BY o.id DESC, o.timestamp DESC ";
168
+ }
169
+ else
170
+ {
171
+ $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS id FROM $wpdb->pmpro_membership_orders WHERE ".$condition." ORDER BY id DESC, timestamp DESC ";
172
+ }
173
+
174
+ if(!empty($start) && !empty($limit))
175
+ $sqlQuery .= "LIMIT $start, $limit";
176
+
177
+ $order_ids = $wpdb->get_col($sqlQuery);
178
+
179
+ //begin output
180
+ header("Content-type: text/csv");
181
+
182
+ $filename = "orders.csv";
183
+ /*
184
+ Insert logic here for building filename from $filter and other values.
185
+ */
186
+ header("Content-Disposition: attachment; filename=$filename;");
187
+
188
+ $csvoutput = "id,user_id,user_login,first_name,last_name,user_email,billing_name,billing_street,billing_city,billing_state,billing_zip,billing_country,billing_phone,membership_id,level_name,subtotal,tax,couponamount,total,payment_type,cardtype,accountnumber,expirationmonth,expirationyear,status,gateway,gateway_environment,payment_transaction_id,subscription_transaction_id,discount_code_id,discount_code,timestamp";
189
+
190
+ //these are the meta_keys for the fields (arrays are object, property. so e.g. $theuser->ID)
191
+ $default_columns = array(
192
+ array("order", "id"),
193
+ array("user", "ID"),
194
+ array("user", "user_login"),
195
+ array("user", "first_name"),
196
+ array("user", "last_name"),
197
+ array("user", "user_email"),
198
+ array("order", "billing", "name"),
199
+ array("order", "billing", "street"),
200
+ array("order", "billing", "city"),
201
+ array("order", "billing", "state"),
202
+ array("order", "billing", "zip"),
203
+ array("order", "billing", "country"),
204
+ array("order", "billing", "phone"),
205
+ array("order", "membership_id"),
206
+ array("level", "name"),
207
+ array("order", "subtotal"),
208
+ array("order", "tax"),
209
+ array("order", "couponamount"),
210
+ array("order", "total"),
211
+ array("order", "payment_type"),
212
+ array("order", "cardtype"),
213
+ array("order", "accountnumber"),
214
+ array("order", "expirationmonth"),
215
+ array("order", "expirationyear"),
216
+ array("order", "status"),
217
+ array("order", "gateway"),
218
+ array("order", "gateway_environment"),
219
+ array("order", "payment_transaction_id"),
220
+ array("order", "subscription_transactiond_id"),
221
+ array("discount_code", "id"),
222
+ array("discount_code", "code")
223
+ );
224
+
225
+ //any extra columns
226
+ $extra_columns = apply_filters("pmpro_orders_csv_extra_columns", array());
227
+ if(!empty($extra_columns))
228
+ {
229
+ foreach($extra_columns as $heading => $callback)
230
+ {
231
+ $csvoutput .= "," . $heading;
232
+ }
233
+ }
234
+
235
+ $csvoutput .= "\n";
236
+
237
+ //output
238
+ echo $csvoutput;
239
+ $csvoutput = "";
240
+
241
+ if($order_ids)
242
+ {
243
+ foreach($order_ids as $order_id)
244
+ {
245
+ $order = new MemberOrder();
246
+ $order->nogateway = true;
247
+ $order->getMemberOrderByID($order_id);
248
+ $user = get_userdata($order->user_id);
249
+ $level = $order->getMembershipLevel();
250
+ $sqlQuery = "SELECT c.id, c.code FROM $wpdb->pmpro_discount_codes_uses cu LEFT JOIN $wpdb->pmpro_discount_codes c ON cu.code_id = c.id WHERE cu.order_id = '" . $order_id . "' LIMIT 1";
251
+ $discount_code = $wpdb->get_row($sqlQuery);
252
+
253
+ //default columns
254
+ if(!empty($default_columns))
255
+ {
256
+ $count = 0;
257
+ foreach($default_columns as $col)
258
+ {
259
+ //add comma after the first item
260
+ $count++;
261
+ if($count > 1)
262
+ $csvoutput .= ",";
263
+
264
+ //checking $object->property. note the double $$
265
+ if(!empty($col[2]) && isset($$col[0]->$col[1]->$col[2]))
266
+ $csvoutput .= pmpro_enclose($$col[0]->$col[1]->$col[2]); //output the value
267
+ elseif(!empty($$col[0]->$col[1]))
268
+ $csvoutput .= pmpro_enclose($$col[0]->$col[1]); //output the value
269
+ }
270
+ }
271
+
272
+ //timestamp
273
+ $csvoutput .= "," . pmpro_enclose(date(get_option("date_format"), $order->timestamp));
274
+
275
+ //any extra columns
276
+ if(!empty($extra_columns))
277
+ {
278
+ foreach($extra_columns as $heading => $callback)
279
+ {
280
+ $csvoutput .= "," . pmpro_enclose(call_user_func($callback, $order));
281
+ }
282
+ }
283
+
284
+ $csvoutput .= "\n";
285
+
286
+ //output
287
+ echo $csvoutput;
288
+ $csvoutput = "";
289
+ }
290
+ }
291
+
292
+ print $csvoutput;
293
+
294
+ function pmpro_enclose($s)
295
+ {
296
+ return "\"" . str_replace("\"", "\\\"", $s) . "\"";
297
+ }
adminpages/orders.php ADDED
@@ -0,0 +1,996 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //only admins can get this
3
+ if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_orders")))
4
+ {
5
+ die(__("You do not have permissions to perform this action.", "pmpro"));
6
+ }
7
+
8
+ //vars
9
+ global $wpdb;
10
+ if(isset($_REQUEST['s']))
11
+ $s = $_REQUEST['s'];
12
+ else
13
+ $s = "";
14
+
15
+ if(isset($_REQUEST['l']))
16
+ $l = $_REQUEST['l'];
17
+ else
18
+ $l = false;
19
+
20
+ if(isset($_REQUEST['start-month']))
21
+ $start_month = $_REQUEST['start-month'];
22
+ else
23
+ $start_month = "1";
24
+
25
+ if(isset($_REQUEST['start-day']))
26
+ $start_day = $_REQUEST['start-day'];
27
+ else
28
+ $start_day = "1";
29
+
30
+ if(isset($_REQUEST['start-year']))
31
+ $start_year = $_REQUEST['start-year'];
32
+ else
33
+ $start_year = date("Y");
34
+
35
+ if(isset($_REQUEST['end-month']))
36
+ $end_month = $_REQUEST['end-month'];
37
+ else
38
+ $end_month = date("n");
39
+
40
+ if(isset($_REQUEST['end-day']))
41
+ $end_day = $_REQUEST['end-day'];
42
+ else
43
+ $end_day = date("j");
44
+
45
+ if(isset($_REQUEST['end-year']))
46
+ $end_year = $_REQUEST['end-year'];
47
+ else
48
+ $end_year = date("Y");
49
+
50
+ if(isset($_REQUEST['predefined-date']))
51
+ $predefined_date = $_REQUEST['predefined-date'];
52
+ else
53
+ $predefined_date = "This Month";
54
+
55
+ if(isset($_REQUEST['status']))
56
+ $status = $_REQUEST['status'];
57
+ else
58
+ $status = "";
59
+
60
+
61
+ //deleting?
62
+ if(!empty($_REQUEST['delete']))
63
+ {
64
+ $dorder = new MemberOrder(intval($_REQUEST['delete']));
65
+ if($dorder->deleteMe())
66
+ {
67
+ $pmpro_msg = __("Order deleted successfully.", "pmpro");
68
+ $pmpro_msgt = "success";
69
+ }
70
+ else
71
+ {
72
+ $pmpro_msg = __("Error deleting order.", "pmpro");
73
+ $pmpro_msgt = "error";
74
+ }
75
+ }
76
+
77
+ if(isset($_REQUEST['filter']))
78
+ $filter = sanitize_text_field($_REQUEST['filter']);
79
+ else
80
+ $filter = "all";
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
+
89
+ //saving?
90
+ if(!empty($_REQUEST['save']))
91
+ {
92
+ //start with old order if applicable
93
+ $order_id = intval($_REQUEST['order']);
94
+ if($order_id > 0)
95
+ $order = new MemberOrder($order_id);
96
+ else
97
+ $order = new MemberOrder();
98
+
99
+ //update values
100
+ if(!in_array("code", $read_only_fields))
101
+ $order->code = $_POST['code'];
102
+ if(!in_array("user_id", $read_only_fields))
103
+ $order->user_id = intval($_POST['user_id']);
104
+ if(!in_array("membership_id", $read_only_fields))
105
+ $order->membership_id = intval($_POST['membership_id']);
106
+ if(!in_array("billing_name", $read_only_fields))
107
+ $order->billing->name = stripslashes($_POST['billing_name']);
108
+ if(!in_array("billing_street", $read_only_fields))
109
+ $order->billing->street = stripslashes($_POST['billing_street']);
110
+ if(!in_array("billing_city", $read_only_fields))
111
+ $order->billing->city = stripslashes($_POST['billing_city']);
112
+ if(!in_array("billing_state", $read_only_fields))
113
+ $order->billing->state = stripslashes($_POST['billing_state']);
114
+ if(!in_array("billing_zip", $read_only_fields))
115
+ $order->billing->zip = $_POST['billing_zip'];
116
+ if(!in_array("billing_country", $read_only_fields))
117
+ $order->billing->country = stripslashes($_POST['billing_country']);
118
+ if(!in_array("billing_phone", $read_only_fields))
119
+ $order->billing->phone = $_POST['billing_phone'];
120
+ if(!in_array("subtotal", $read_only_fields))
121
+ $order->subtotal = $_POST['subtotal'];
122
+ if(!in_array("tax", $read_only_fields))
123
+ $order->tax = $_POST['tax'];
124
+ if(!in_array("couponamount", $read_only_fields))
125
+ $order->couponamount = $_POST['couponamount'];
126
+ if(!in_array("total", $read_only_fields))
127
+ $order->total = $_POST['total'];
128
+ if(!in_array("payment_type", $read_only_fields))
129
+ $order->payment_type = $_POST['payment_type'];
130
+ if(!in_array("cardtype", $read_only_fields))
131
+ $order->cardtype = $_POST['cardtype'];
132
+ if(!in_array("accountnumber", $read_only_fields))
133
+ $order->accountnumber = $_POST['accountnumber'];
134
+ if(!in_array("expirationmonth", $read_only_fields))
135
+ $order->expirationmonth = $_POST['expirationmonth'];
136
+ if(!in_array("expirationyear", $read_only_fields))
137
+ $order->expirationyear = $_POST['expirationyear'];
138
+ if(!in_array("ExpirationDate", $read_only_fields))
139
+ $order->ExpirationDate = $order->expirationmonth . $order->expirationyear;
140
+ if(!in_array("status", $read_only_fields))
141
+ $order->status = stripslashes($_POST['status']);
142
+ if(!in_array("gateway", $read_only_fields))
143
+ $order->gateway = $_POST['gateway'];
144
+ if(!in_array("gateway_environment", $read_only_fields))
145
+ $order->gateway_environment = $_POST['gateway_environment'];
146
+ if(!in_array("payment_transaction_id", $read_only_fields))
147
+ $order->payment_transaction_id = $_POST['payment_transaction_id'];
148
+ if(!in_array("subscription_transaction_id", $read_only_fields))
149
+ $order->subscription_transaction_id = $_POST['subscription_transaction_id'];
150
+ if(!in_array("notes", $read_only_fields))
151
+ $order->notes = stripslashes($_POST['notes']);
152
+
153
+ //affiliate stuff
154
+ $affiliates = apply_filters("pmpro_orders_show_affiliate_ids", false);
155
+ if(!empty($affiliates))
156
+ {
157
+ if(!in_array("affiliate_id", $read_only_fields))
158
+ $order->affiliate_id = $_POST['affiliate_id'];
159
+ if(!in_array("affiliate_subid", $read_only_fields))
160
+ $order->affiliate_subid = $_POST['affiliate_subid'];
161
+ }
162
+
163
+ //save
164
+ if($order->saveOrder() !== false)
165
+ {
166
+ //handle timestamp
167
+ if($order->updateTimestamp($_POST['ts_year'], $_POST['ts_month'], $_POST['ts_day']) !== false)
168
+ {
169
+ $pmpro_msg = __("Order saved successfully.", "pmpro");
170
+ $pmpro_msgt = "success";
171
+ }
172
+ else
173
+ {
174
+ $pmpro_msg = __("Error updating order timestamp.", "pmpro");
175
+ $pmpro_msgt = "error";
176
+ }
177
+ }
178
+ else
179
+ {
180
+ $pmpro_msg = __("Error saving order.", "pmpro");
181
+ $pmpro_msgt = "error";
182
+ }
183
+ }
184
+ else
185
+ {
186
+ //order passed?
187
+ if(!empty($_REQUEST['order']))
188
+ {
189
+ $order_id = intval($_REQUEST['order']);
190
+ if($order_id > 0)
191
+ $order = new MemberOrder($order_id);
192
+ elseif(!empty($_REQUEST['copy']))
193
+ {
194
+ $order = new MemberOrder(intval($_REQUEST['copy']));
195
+
196
+ //new id
197
+ $order->id = NULL;
198
+
199
+ //new code
200
+ $order->code = $order->getRandomCode();
201
+ }
202
+ else
203
+ {
204
+ $order = new MemberOrder(); //new order
205
+
206
+ //defaults
207
+ $order->code = $order->getRandomCode();
208
+ $order->user_id = "";
209
+ $order->membership_id = "";
210
+ $order->billing->name = "";
211
+ $order->billing->street = "";
212
+ $order->billing->city = "";
213
+ $order->billing->state = "";
214
+ $order->billing->zip = "";
215
+ $order->billing->country = "";
216
+ $order->billing->phone = "";
217
+ $order->subtotal = "";
218
+ $order->tax = "";
219
+ $order->couponamount = "";
220
+ $order->total = "";
221
+ $order->payment_type = "";
222
+ $order->cardtype = "";
223
+ $order->accountnumber = "";
224
+ $order->expirationmonth = "";
225
+ $order->expirationyear = "";
226
+ $order->status = "success";
227
+ $order->gateway = pmpro_getOption("gateway");
228
+ $order->gateway_environment = pmpro_getOption("gateway_environment");
229
+ $order->payment_transaction_id = "";
230
+ $order->subscription_transaction_id = "";
231
+ $order->affiliate_id = "";
232
+ $order->affiliate_subid = "";
233
+ $order->notes = "";
234
+ }
235
+ }
236
+ }
237
+
238
+ require_once(dirname(__FILE__) . "/admin_header.php");
239
+ ?>
240
+
241
+ <?php if(!empty($order)) { ?>
242
+
243
+ <h2>
244
+ <?php if(!empty($order->id)) { ?>
245
+ <?php _e('Order', 'pmpro');?> #<?php echo $order->id?>: <?php echo $order->code?>
246
+ <?php } else { ?>
247
+ <?php _e('New Order', 'pmpro');?>
248
+ <?php } ?>
249
+ </h2>
250
+
251
+ <?php if(!empty($pmpro_msg)) { ?>
252
+ <div id="message" class="<?php if($pmpro_msgt == "success") echo "updated fade"; else echo "error"; ?>"><p><?php echo $pmpro_msg?></p></div>
253
+ <?php } ?>
254
+
255
+ <form method="post" action="">
256
+
257
+ <table class="form-table">
258
+ <tbody>
259
+ <tr>
260
+ <th scope="row" valign="top"><label>ID:</label></th>
261
+ <td><?php if(!empty($order->id)) echo $order->id; else echo __("This will be generated when you save.", "pmpro");?></td>
262
+ </tr>
263
+
264
+ <tr>
265
+ <th scope="row" valign="top"><label for="code"><?php _e('Code', 'pmpro');?>:</label></th>
266
+ <td>
267
+ <?php if(in_array("code", $read_only_fields)) { echo $order->code; } else { ?>
268
+ <input id="code" name="code" type="text" size="50" value="<?php echo esc_attr($order->code);?>" />
269
+ <?php } ?>
270
+ <?php if($order_id < 0) { ?><small class="pmpro_lite"><?php _e('Randomly generated for you.', 'pmpro');?></small><?php } ?>
271
+ </td>
272
+ </tr>
273
+
274
+ <tr>
275
+ <th scope="row" valign="top"><label for="user_id"><?php _e('User ID', 'pmpro');?>:</label></th>
276
+ <td>
277
+ <?php if(in_array("user_id", $read_only_fields) && $order_id > 0) { echo $order->user_id; } else { ?>
278
+ <input id="user_id" name="user_id" type="text" size="50" value="<?php echo esc_attr($order->user_id);?>" />
279
+ <?php } ?>
280
+ </td>
281
+ </tr>
282
+
283
+ <tr>
284
+ <th scope="row" valign="top"><label for="membership_id"><?php _e('Membership Level ID', 'pmpro');?>:</label></th>
285
+ <td>
286
+ <?php if(in_array("membership_id", $read_only_fields) && $order_id > 0) { echo $order->membership_id; } else { ?>
287
+ <input id="membership_id" name="membership_id" type="text" size="50" value="<?php echo esc_attr($order->membership_id);?>" />
288
+ <?php } ?>
289
+ </td>
290
+ </tr>
291
+
292
+ <tr>
293
+ <th scope="row" valign="top"><label for="billing_name"><?php _e('Billing Name', 'pmpro');?>:</label></th>
294
+ <td>
295
+ <?php if(in_array("billing_name", $read_only_fields) && $order_id > 0) { echo $order->billing_name; } else { ?>
296
+ <input id="billing_name" name="billing_name" type="text" size="50" value="<?php echo esc_attr($order->billing->name);?>" />
297
+ <?php } ?>
298
+ </td>
299
+ </tr>
300
+ <tr>
301
+ <th scope="row" valign="top"><label for="billing_street"><?php _e('Billing Street', 'pmpro');?>:</label></th>
302
+ <td>
303
+ <?php if(in_array("billing_street", $read_only_fields) && $order_id > 0) { echo $order->billing_street; } else { ?>
304
+ <input id="billing_street" name="billing_street" type="text" size="50" value="<?php echo esc_attr($order->billing->street);?>" /></td>
305
+ <?php } ?>
306
+ </tr>
307
+ <tr>
308
+ <th scope="row" valign="top"><label for="billing_city"><?php _e('Billing City', 'pmpro');?>:</label></th>
309
+ <td>
310
+ <?php if(in_array("billing_city", $read_only_fields) && $order_id > 0) { echo $order->billing_city; } else { ?>
311
+ <input id="billing_city" name="billing_city" type="text" size="50" value="<?php echo esc_attr($order->billing->city);?>" /></td>
312
+ <?php } ?>
313
+ </tr>
314
+ <tr>
315
+ <th scope="row" valign="top"><label for="billing_state"><?php _e('Billing State', 'pmpro');?>:</label></th>
316
+ <td>
317
+ <?php if(in_array("billing_state", $read_only_fields) && $order_id > 0) { echo $order->billing_state; } else { ?>
318
+ <input id="billing_state" name="billing_state" type="text" size="50" value="<?php echo esc_attr($order->billing->state);?>" /></td>
319
+ <?php } ?>
320
+ </tr>
321
+ <tr>
322
+ <th scope="row" valign="top"><label for="billing_zip"><?php _e('Billing Postal Code', 'pmpro');?>:</label></th>
323
+ <td>
324
+ <?php if(in_array("billing_zip", $read_only_fields) && $order_id > 0) { echo $order->billing_zip; } else { ?>
325
+ <input id="billing_zip" name="billing_zip" type="text" size="50" value="<?php echo esc_attr($order->billing->zip);?>" /></td>
326
+ <?php } ?>
327
+ </tr>
328
+ <tr>
329
+ <th scope="row" valign="top"><label for="billing_country"><?php _e('Billing Country', 'pmpro');?>:</label></th>
330
+ <td>
331
+ <?php if(in_array("billing_country", $read_only_fields) && $order_id > 0) { echo $order->billing_country; } else { ?>
332
+ <input id="billing_country" name="billing_country" type="text" size="50" value="<?php echo esc_attr($order->billing->country);?>" />
333
+ <?php } ?>
334
+ </td>
335
+ </tr>
336
+ <tr>
337
+ <th scope="row" valign="top"><label for="billing_phone"><?php _e('Billing Phone', 'pmpro');?>:</label></th>
338
+ <td>
339
+ <?php if(in_array("billing_phone", $read_only_fields) && $order_id > 0) { echo $order->billing_phone; } else { ?>
340
+ <input id="billing_phone" name="billing_phone" type="text" size="50" value="<?php echo esc_attr($order->billing->phone);?>" />
341
+ <?php } ?>
342
+ </td>
343
+ </tr>
344
+
345
+ <tr>
346
+ <th scope="row" valign="top"><label for="subtotal"><?php _e('Sub Total', 'pmpro');?>:</label></th>
347
+ <td>
348
+ <?php if(in_array("subtotal", $read_only_fields) && $order_id > 0) { echo $order->subtotal; } else { ?>
349
+ <input id="subtotal" name="subtotal" type="text" size="10" value="<?php echo esc_attr($order->subtotal);?>" />
350
+ <?php } ?>
351
+ </td>
352
+ </tr>
353
+ <tr>
354
+ <th scope="row" valign="top"><label for="tax"><?php _e('Tax', 'pmpro');?>:</label></th>
355
+ <td>
356
+ <?php if(in_array("tax", $read_only_fields) && $order_id > 0) { echo $order->tax; } else { ?>
357
+ <input id="tax" name="tax" type="text" size="10" value="<?php echo esc_attr($order->tax);?>" />
358
+ <?php } ?>
359
+ </td>
360
+ </tr>
361
+ <tr>
362
+ <th scope="row" valign="top"><label for="couponamount"><?php _e('Coupon Amount', 'pmpro');?>:</label></th>
363
+ <td>
364
+ <?php if(in_array("couponamount", $read_only_fields) && $order_id > 0) { echo $order->couponamount; } else { ?>
365
+ <input id="couponamount" name="couponamount" type="text" size="10" value="<?php echo esc_attr($order->couponamount);?>" />
366
+ <?php } ?>
367
+ </td>
368
+ </tr>
369
+ <tr>
370
+ <th scope="row" valign="top"><label for="total"><?php _e('Total', 'pmpro');?>:</label></th>
371
+ <td>
372
+ <?php if(in_array("total", $read_only_fields) && $order_id > 0) { echo $order->total; } else { ?>
373
+ <input id="total" name="total" type="text" size="10" value="<?php echo esc_attr($order->total);?>" />
374
+ <?php } ?>
375
+ <small class="pmpro_lite"><?php _e('Should be subtotal + tax - couponamount.', 'pmpro');?></small>
376
+ </td>
377
+ </tr>
378
+
379
+ <tr>
380
+ <th scope="row" valign="top"><label for="payment_type"><?php _e('Payment Type', 'pmpro');?>:</label></th>
381
+ <td>
382
+ <?php if(in_array("payment_type", $read_only_fields) && $order_id > 0) { echo $order->payment_type; } else { ?>
383
+ <input id="payment_type" name="payment_type" type="text" size="50" value="<?php echo esc_attr($order->payment_type);?>" />
384
+ <?php } ?>
385
+ <small class="pmpro_lite"><?php _e('e.g. PayPal Express, PayPal Standard, Credit Card.', 'pmpro');?></small>
386
+ </td>
387
+ </tr>
388
+ <tr>
389
+ <th scope="row" valign="top"><label for="cardtype"><?php _e('Card Type', 'pmpro');?></label></th>
390
+ <td>
391
+ <?php if(in_array("cardtype", $read_only_fields) && $order_id > 0) { echo $order->cardtype; } else { ?>
392
+ <input id="cardtype" name="cardtype" type="text" size="50" value="<?php echo esc_attr($order->cardtype);?>" />
393
+ <?php } ?>
394
+ <small class="pmpro_lite"><?php _e('e.g. Visa, MasterCard, AMEX, etc', 'pmpro');?></small>
395
+ </td>
396
+ </tr>
397
+ <tr>
398
+ <th scope="row" valign="top"><label for="accountnumber"><?php _e('Account Number', 'pmpro');?>:</label></th>
399
+ <td>
400
+ <?php if(in_array("accountnumber", $read_only_fields) && $order_id > 0) { echo $order->accountnumber; } else { ?>
401
+ <input id="accountnumber" name="accountnumber" type="text" size="50" value="<?php echo esc_attr($order->accountnumber);?>" />
402
+ <?php } ?>
403
+ <small class="pmpro_lite"><?php _e('Obscure all but last 4 digits.', 'pmpro');?></small>
404
+ </td>
405
+ </tr>
406
+ <?php if(in_array("ExpirationDate", $read_only_fields) && $order_id > 0) { echo $order->ExpirationDate; } else { ?>
407
+ <tr>
408
+ <th scope="row" valign="top"><label for="expirationmonth"><?php _e('Expiration Month', 'pmpro');?>:</label></th>
409
+ <td>
410
+ <input id="expirationmonth" name="expirationmonth" type="text" size="10" value="<?php echo esc_attr($order->expirationmonth);?>" />
411
+ <small class="pmpro_lite">MM</small>
412
+ </td>
413
+ </tr>
414
+ <tr>
415
+ <th scope="row" valign="top"><label for="expirationyear"><?php _e('Expiration Year', 'pmpro');?>:</label></th>
416
+ <td>
417
+ <input id="expirationyear" name="expirationyear" type="text" size="10" value="<?php echo esc_attr($order->expirationyear);?>" />
418
+ <small class="pmpro_lite">YYYY</small>
419
+ </td>
420
+ </tr>
421
+ <?php } ?>
422
+ <tr>
423
+ <th scope="row" valign="top"><label for="status"><?php _e('Status', 'pmpro');?>:</label></th>
424
+ <td>
425
+ <?php if(in_array("status", $read_only_fields) && $order_id > 0) { echo $order->status; } else { ?>
426
+ <?php
427
+ $statuses = array();
428
+ $default_statuses = array("", "success", "cancelled", "review", "token", "refunded", "pending");
429
+ $used_statuses = $wpdb->get_col("SELECT DISTINCT(status) FROM $wpdb->pmpro_membership_orders");
430
+ $statuses = array_unique(array_merge($default_statuses, $used_statuses));
431
+ asort($statuses);
432
+ $statuses = apply_filters("pmpro_order_statuses", $statuses);
433
+ ?>
434
+ <select id="status" name="status">
435
+ <?php foreach($statuses as $status) { ?>
436
+ <option value="<?php echo esc_attr($status);?>" <?php selected($order->status, $status);?>><?php echo $status;?></option>
437
+ <?php } ?>
438
+ </select>
439
+ <?php } ?>
440
+ </td>
441
+ </tr>
442
+
443
+ <tr>
444
+ <th scope="row" valign="top"><label for="gateway"><?php _e('Gateway', 'pmpro');?>:</label></th>
445
+ <td>
446
+ <?php if(in_array("gateway", $read_only_fields) && $order_id > 0) { echo $order->gateway; } else { ?>
447
+ <select id="gateway" name="gateway" onchange="pmpro_changeGateway(jQuery(this).val());">
448
+ <option value="" <?php if(empty($order->gateway)) { ?>selected="selected"<?php } ?>><?php _e('Testing Only', 'pmpro');?></option>
449
+ <option value="check" <?php if($order->gateway == "check") { ?>selected="selected"<?php } ?>><?php _e('Pay by Check', 'pmpro');?></option>
450
+ <option value="stripe" <?php if($order->gateway == "stripe") { ?>selected="selected"<?php } ?>>Stripe</option>
451
+ <option value="paypalstandard" <?php if($order->gateway == "paypalstandard") { ?>selected="selected"<?php } ?>>PayPal Standard</option>
452
+ <option value="paypalexpress" <?php if($order->gateway == "paypalexpress") { ?>selected="selected"<?php } ?>>PayPal Express</option>
453
+ <option value="paypal" <?php if($order->gateway == "paypal") { ?>selected="selected"<?php } ?>>PayPal Website Payments Pro</option>
454
+ <option value="payflowpro" <?php if($order->gateway == "payflowpro") { ?>selected="selected"<?php } ?>>PayPal Payflow Pro</option>
455
+ <option value="authorizenet" <?php if($order->gateway == "authorizenet") { ?>selected="selected"<?php } ?>>Authorize.net</option>
456
+ </select>
457
+ <?php } ?>
458
+ </td>
459
+ </tr>
460
+ <tr>
461
+ <th scope="row" valign="top"><label for="gateway_environment"><?php _e('Gateway Environment', 'pmpro');?>:</label></th>
462
+ <td>
463
+ <?php if(in_array("gateway_environment", $read_only_fields) && $order_id > 0) { echo $order->gateway_environment; } else { ?>
464
+ <select name="gateway_environment">
465
+ <option value="sandbox" <?php if($order->gateway_environment == "sandbox") { ?>selected="selected"<?php } ?>><?php _e('Sandbox/Testing', 'pmpro');?></option>
466
+ <option value="live" <?php if($order->gateway_environment == "live") { ?>selected="selected"<?php } ?>><?php _e('Live/Production', 'pmpro');?></option>
467
+ </select>
468
+ <?php } ?>
469
+ </td>
470
+ </tr>
471
+
472
+ <tr>
473
+ <th scope="row" valign="top"><label for="payment_transaction_id"><?php _e('Payment Transaction ID', 'pmpro');?>:</label></th>
474
+ <td>
475
+ <?php if(in_array("payment_transaction_id", $read_only_fields) && $order_id > 0) { echo $order->payment_transaction_id; } else { ?>
476
+ <input id="payment_transaction_id" name="payment_transaction_id" type="text" size="50" value="<?php echo esc_attr($order->payment_transaction_id);?>" />
477
+ <?php } ?>
478
+ <small class="pmpro_lite"><?php _e('Generated by the gateway. Useful to cross reference orders.', 'pmpro');?></small>
479
+ </td>
480
+ </tr>
481
+ <tr>
482
+ <th scope="row" valign="top"><label for="subscription_transaction_id"><?php _e('Subscription Transaction ID', 'pmpro');?>:</label></th>
483
+ <td>
484
+ <?php if(in_array("subscription_transaction_id", $read_only_fields) && $order_id > 0) { echo $order->subscription_transaction_id; } else { ?>
485
+ <input id="subscription_transaction_id" name="subscription_transaction_id" type="text" size="50" value="<?php echo esc_attr($order->subscription_transaction_id);?>" />
486
+ <?php } ?>
487
+ <small class="pmpro_lite"><?php _e('Generated by the gateway. Useful to cross reference subscriptions.', 'pmpro');?></small>
488
+ </td>
489
+ </tr>
490
+
491
+ <tr>
492
+ <th scope="row" valign="top"><label for="ts_month"><?php _e('Date', 'pmpro');?>:</label></th>
493
+ <td>
494
+ <?php if(in_array("timestamp", $read_only_fields) && $order_id > 0) { echo date(option("date_format"), $order->timestamp); } else { ?>
495
+ <?php
496
+ //setup date vars
497
+ if(!empty($order->timestamp))
498
+ $timestamp = $order->timestamp;
499
+ else
500
+ $timestamp = current_time('timestamp');
501
+
502
+ $year = date("Y", $timestamp);
503
+ $month = date("n", $timestamp);
504
+ $day = date("j", $timestamp);
505
+ ?>
506
+ <select id="ts_month" name="ts_month">
507
+ <?php
508
+ for($i = 1; $i < 13; $i++)
509
+ {
510
+ ?>
511
+ <option value="<?php echo $i?>" <?php if($i == $month) { ?>selected="selected"<?php } ?>><?php echo date("M", strtotime($i . "/1/" . $year, current_time("timestamp")))?></option>
512
+ <?php
513
+ }
514
+ ?>
515
+ </select>
516
+ <input name="ts_day" type="text" size="2" value="<?php echo $day?>" />
517
+ <input name="ts_year" type="text" size="4" value="<?php echo $year?>" />
518
+ <?php } ?>
519
+ </td>
520
+ </tr>
521
+
522
+ <?php
523
+ $affiliates = apply_filters("pmpro_orders_show_affiliate_ids", false);
524
+ if(!empty($affiliates)) {
525
+ ?>
526
+ <tr>
527
+ <th scope="row" valign="top"><label for="affiliate_id"><?php _e('Affiliate ID', 'pmpro');?>Affiliate ID:</label></th>
528
+ <td>
529
+ <?php if(in_array("affiliate_id", $read_only_fields) && $order_id > 0) { echo $order->affiliate_id; } else { ?>
530
+ <input id="affiliate_id" name="affiliate_id" type="text" size="50" value="<?php echo esc_attr($order->affiliate_id);?>" />
531
+ <?php } ?>
532
+ </td>
533
+ </tr>
534
+ <tr>
535
+ <th scope="row" valign="top"><label for="affiliate_subid"><?php _e('Affiliate SubID', 'pmpro');?>Affiliate SubID:</label></th>
536
+ <td>
537
+ <?php if(in_array("affiliate_subid", $read_only_fields) && $order_id > 0) { echo $order->affiliate_subid; } else { ?>
538
+ <input id="affiliate_subid" name="affiliate_subid" type="text" size="50" value="<?php echo esc_attr($order->affiliate_subid);?>" />
539
+ <?php } ?>
540
+ </td>
541
+ </tr>
542
+ <?php } ?>
543
+
544
+ <tr>
545
+ <th scope="row" valign="top"><label for="notes"><?php _e('Notes', 'pmpro');?>:</label></th>
546
+ <td>
547
+ <?php if(in_array("notes", $read_only_fields) && $order_id > 0) { echo $order->notes; } else { ?>
548
+ <textarea id="notes" name="notes" rows="5" cols="80"><?php echo esc_textarea($order->notes);?></textarea>
549
+ <?php } ?>
550
+ </td>
551
+ </tr>
552
+
553
+ <?php do_action("pmpro_after_order_settings", $order); ?>
554
+
555
+ </tbody>
556
+ </table>
557
+
558
+ <p class="submit topborder">
559
+ <input name="order" type="hidden" value="<?php if(!empty($order->id)) echo $order->id; else echo $order_id;?>" />
560
+ <input name="save" type="submit" class="button-primary" value="<?php _e('Save Order', 'pmpro');?>" />
561
+ <input name="cancel" type="button" class="cancel button-secondary" value="<?php _e('Cancel', 'pmpro');?>" onclick="location.href='<?php echo get_admin_url(NULL, '/admin.php?page=pmpro-orders')?>';" />
562
+ </p>
563
+
564
+ </form>
565
+
566
+ <?php } else { ?>
567
+
568
+ <form id="posts-filter" method="get" action="">
569
+ <h2>
570
+ <?php _e('Orders', 'pmpro');?>
571
+ <a href="admin.php?page=pmpro-orders&order=-1" class="add-new-h2">+ <?php _e('Add New Order', 'pmpro');?></a>
572
+
573
+ <?php
574
+ //build the export URL
575
+ $export_url = admin_url('admin-ajax.php') . "?action=orders_csv";
576
+ $url_params = array(
577
+ "filter"=>$filter,
578
+ "s"=>$s,
579
+ "l"=>$l,
580
+ "start-month"=>$start_month,
581
+ "start-day"=>$start_day,
582
+ "start-year"=>$start_year,
583
+ "end-month"=>$end_month,
584
+ "end-day"=>$end_day,
585
+ "end-year"=>$end_year,
586
+ "predefined-date"=>$predefined_date,
587
+ "status"=>$status
588
+ );
589
+ $export_url = add_query_arg($url_params, $export_url);
590
+ ?>
591
+ <a target="_blank" href="<?php echo $export_url;?>" class="add-new-h2"><?php _e('Export to CSV', 'pmpro');?></a>
592
+ </h2>
593
+
594
+
595
+
596
+ <?php if(!empty($pmpro_msg)) { ?>
597
+ <div id="message" class="<?php if($pmpro_msgt == "success") echo "updated fade"; else echo "error"; ?>"><p><?php echo $pmpro_msg?></p></div>
598
+ <?php } ?>
599
+
600
+
601
+ <ul class="subsubsub">
602
+ <li>
603
+ <?php _ex('Show', 'Dropdown label, e.g. Show Daily Orders for January', 'pmpro')?>
604
+ <select id="filter" name="filter">
605
+ <option value="all" <?php selected($filter, "all");?>><?php _e('All', 'pmpro');?></option>
606
+ <option value="within-a-date-range" <?php selected($filter, "within-a-date-range");?>><?php _e('Within a Date Range', 'pmpro');?></option>
607
+ <option value="predefined-date-range" <?php selected($filter, "predefined-date-range");?>><?php _e('Predefined Date Range', 'pmpro');?></option>
608
+ <option value="within-a-level" <?php selected($filter, "within-a-level");?>><?php _e('Within a Level', 'pmpro');?></option>
609
+ <option value="within-a-status" <?php selected($filter, "within-a-status");?>><?php _e('Within a Status', 'pmpro');?></option>
610
+ </select>
611
+
612
+ <span id="from"><?php _ex('From', 'Dropdown label', 'pmpro')?></span>
613
+
614
+ <select id="start-month" name="start-month">
615
+ <?php for($i = 1; $i < 13; $i++) { ?>
616
+ <option value="<?php echo $i;?>" <?php selected($start_month, $i);?>><?php echo date("F", mktime(0, 0, 0, $i, 2));?></option>
617
+ <?php } ?>
618
+ </select>
619
+
620
+ <input id='start-day' name="start-day" type="text" size="2" value="<?php echo $start_day?>" />
621
+ <input id='start-year' name="start-year" type="text" size="4" value="<?php echo $start_year?>" />
622
+
623
+
624
+ <span id="to"><?php _ex('To', 'Dropdown label', 'pmpro')?></span>
625
+
626
+ <select id="end-month" name="end-month">
627
+ <?php for($i = 1; $i < 13; $i++) { ?>
628
+ <option value="<?php echo $i;?>" <?php selected($end_month, $i);?>><?php echo date("F", mktime(0, 0, 0, $i,2));?></option>
629
+ <?php } ?>
630
+ </select>
631
+
632
+
633
+ <input id='end-day' name="end-day" type="text" size="2" value="<?php echo $end_day?>" />
634
+ <input id='end-year' name="end-year" type="text" size="4" value="<?php echo $end_year?>" />
635
+
636
+ <span id="filterby"><?php _ex('filter by ', 'Dropdown label', 'pmpro')?></span>
637
+
638
+ <select id="predefined-date" name="predefined-date">
639
+
640
+ <option value="<?php echo "This Month";?>" <?php selected($predefined_date, "This Month");?>><?php echo "This Month";?></option>
641
+ <option value="<?php echo "Last Month";?>" <?php selected($predefined_date, "Last Month");?>><?php echo "Last Month";?></option>
642
+ <option value="<?php echo "This Year";?>" <?php selected($predefined_date, "This Year");?>><?php echo "This Year";?></option>
643
+ <option value="<?php echo "Last Year";?>" <?php selected($predefined_date, "Last Year");?>><?php echo "Last Year";?></option>
644
+
645
+ </select>
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) { ?>
654
+ <option value="<?php echo $level->id;?>" <?php selected($l, $level->id);?>><?php echo $level->name;?></option>
655
+ <?php } ?>
656
+
657
+ </select>
658
+
659
+ <?php
660
+ $statuses = array();
661
+ $default_statuses = array("", "success", "cancelled", "review", "token", "refunded");
662
+ $used_statuses = $wpdb->get_col("SELECT DISTINCT(status) FROM $wpdb->pmpro_membership_orders");
663
+ $statuses = array_unique(array_merge($default_statuses, $used_statuses));
664
+ asort($statuses);
665
+ $statuses = apply_filters("pmpro_order_statuses", $statuses);
666
+ ?>
667
+ <select id="status" name="status">
668
+ <?php foreach($statuses as $the_status) { ?>
669
+ <option value="<?php echo esc_attr($the_status);?>" <?php selected($the_status, $status);?>><?php echo $the_status;?></option>
670
+ <?php } ?>
671
+ </select>
672
+
673
+
674
+ <input id="submit" type="submit" value="<?php _ex('Filter', 'Submit button value.', 'pmpro');?>" />
675
+ </li>
676
+ </ul>
677
+
678
+ <script>
679
+ //update month/year when period dropdown is changed
680
+ jQuery(document).ready(function() {
681
+ jQuery('#filter').change(function() {
682
+ pmpro_ShowMonthOrYear();
683
+ });
684
+ });
685
+
686
+ function pmpro_ShowMonthOrYear()
687
+ {
688
+ var filter = jQuery('#filter').val();
689
+ if(filter == 'all')
690
+ {
691
+ jQuery('#start-month').hide();
692
+ jQuery('#start-day').hide();
693
+ jQuery('#start-year').hide();
694
+ jQuery('#end-month').hide();
695
+ jQuery('#end-day').hide();
696
+ jQuery('#end-year').hide();
697
+ jQuery('#predefined-date').hide();
698
+ jQuery('#status').hide();
699
+ jQuery('#l').hide();
700
+ jQuery('#from').hide();
701
+ jQuery('#to').hide();
702
+ jQuery('#submit').show();
703
+ jQuery('#filterby').hide();
704
+ }
705
+ else if(filter == 'within-a-date-range')
706
+ {
707
+ jQuery('#start-month').show();
708
+ jQuery('#start-day').show();
709
+ jQuery('#start-year').show();
710
+ jQuery('#end-month').show();
711
+ jQuery('#end-day').show();
712
+ jQuery('#end-year').show();
713
+ jQuery('#predefined-date').hide();
714
+ jQuery('#status').hide();
715
+ jQuery('#l').hide();
716
+ jQuery('#submit').show();
717
+ jQuery('#from').show();
718
+ jQuery('#to').show();
719
+ jQuery('#filterby').hide();
720
+ }
721
+ else if(filter == 'predefined-date-range')
722
+ {
723
+ jQuery('#start-month').hide();
724
+ jQuery('#start-day').hide();
725
+ jQuery('#start-year').hide();
726
+ jQuery('#end-month').hide();
727
+ jQuery('#end-day').hide();
728
+ jQuery('#end-year').hide();
729
+ jQuery('#predefined-date').show();
730
+ jQuery('#status').hide();
731
+ jQuery('#l').hide();
732
+ jQuery('#submit').show();
733
+ jQuery('#from').hide();
734
+ jQuery('#to').hide();
735
+ jQuery('#filterby').show();
736
+ }
737
+ else if(filter == 'within-a-level')
738
+ {
739
+ jQuery('#start-month').hide();
740
+ jQuery('#start-day').hide();
741
+ jQuery('#start-year').hide();
742
+ jQuery('#end-month').hide();
743
+ jQuery('#end-day').hide();
744
+ jQuery('#end-year').hide();
745
+ jQuery('#predefined-date').hide();
746
+ jQuery('#status').hide();
747
+ jQuery('#l').show();
748
+ jQuery('#submit').show();
749
+ jQuery('#from').hide();
750
+ jQuery('#to').hide();
751
+ jQuery('#filterby').show();
752
+ }
753
+ else if(filter == 'within-a-status')
754
+ {
755
+ jQuery('#start-month').hide();
756
+ jQuery('#start-day').hide();
757
+ jQuery('#start-year').hide();
758
+ jQuery('#end-month').hide();
759
+ jQuery('#end-day').hide();
760
+ jQuery('#end-year').hide();
761
+ jQuery('#predefined-date').hide();
762
+ jQuery('#status').show();
763
+ jQuery('#l').hide();
764
+ jQuery('#submit').show();
765
+ jQuery('#from').hide();
766
+ jQuery('#to').hide();
767
+ jQuery('#filterby').show();
768
+ }
769
+ }
770
+
771
+ pmpro_ShowMonthOrYear();
772
+
773
+
774
+ </script>
775
+
776
+ <p class="search-box">
777
+ <label class="hidden" for="post-search-input"><?php _e('Search Orders', 'pmpro');?>:</label>
778
+ <input type="hidden" name="page" value="pmpro-orders" />
779
+ <input id="post-search-input" type="text" value="<?php echo $s?>" name="s"/>
780
+ <input class="button" type="submit" value="<?php _e('Search Orders', 'pmpro');?>"/>
781
+ </p>
782
+
783
+ <?php
784
+ //some vars for the search
785
+ if(isset($_REQUEST['pn']))
786
+ $pn = $_REQUEST['pn'];
787
+ else
788
+ $pn = 1;
789
+
790
+ if(isset($_REQUEST['limit']))
791
+ $limit = $_REQUEST['limit'];
792
+ else
793
+ $limit = 15;
794
+
795
+ $end = $pn * $limit;
796
+ $start = $end - $limit;
797
+
798
+ //filters
799
+ if($filter == "all" || !$filter)
800
+ $condition = "1=1";
801
+ elseif($filter == "within-a-date-range")
802
+ {
803
+ $start_date = $start_year."-".$start_month."-".$start_day;
804
+ $end_date = $end_year."-".$end_month."-".$end_day;
805
+
806
+ //add times to dates
807
+ $start_date = $start_date . " 00:00:00";
808
+ $end_date = $end_date . " 23:59:59";
809
+
810
+ $condition = "timestamp BETWEEN '".$start_date."' AND '".$end_date."'";
811
+ }
812
+ elseif($filter == "predefined-date-range")
813
+ {
814
+ if($predefined_date == "Last Month")
815
+ {
816
+ $start_date = date("Y-m-d", strtotime("first day of last month", current_time("timestamp")));
817
+ $end_date = date("Y-m-d", strtotime("last day of last month", current_time("timestamp")));
818
+ }
819
+ elseif($predefined_date == "This Month")
820
+ {
821
+ $start_date = date("Y-m-d", strtotime("first day of this month", current_time("timestamp")));
822
+ $end_date = date("Y-m-d", strtotime("last day of this month", current_time("timestamp")));
823
+ }
824
+ elseif($predefined_date == "This Year")
825
+ {
826
+ $year = date('Y');
827
+ $start_date = date("Y-m-d", strtotime("first day of January $year", current_time("timestamp")));
828
+ $end_date = date("Y-m-d", strtotime("last day of December $year", current_time("timestamp")));
829
+ }
830
+
831
+ elseif($predefined_date == "Last Year")
832
+ {
833
+ $year = date('Y') - 1;
834
+ $start_date = date("Y-m-d", strtotime("first day of January $year", current_time("timestamp")));
835
+ $end_date = date("Y-m-d", strtotime("last day of December $year", current_time("timestamp")));
836
+ }
837
+
838
+ //add times to dates
839
+ $start_date = $start_date . " 00:00:00";
840
+ $end_date = $end_date . " 23:59:59";
841
+
842
+ $condition = "timestamp BETWEEN '".$start_date."' AND '".$end_date."'";
843
+ }
844
+ elseif($filter == "within-a-level")
845
+ {
846
+ $condition = "membership_id = $l";
847
+ }
848
+ elseif($filter == "within-a-status")
849
+ {
850
+ $condition = "status = '$status' ";
851
+ }
852
+
853
+ //string search
854
+ if($s)
855
+ {
856
+ $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS o.id FROM $wpdb->pmpro_membership_orders o LEFT JOIN $wpdb->users u ON o.user_id = u.ID LEFT JOIN $wpdb->pmpro_membership_levels l ON o.membership_id = l.id ";
857
+
858
+ $join_with_usermeta = apply_filters("pmpro_orders_search_usermeta", false);
859
+ if($join_with_usermeta)
860
+ $sqlQuery .= "LEFT JOIN $wpdb->usermeta um ON o.user_id = um.user_id ";
861
+
862
+ $sqlQuery .= "WHERE (1=2 ";
863
+
864
+ $fields = array("o.id", "o.code", "o.billing_name", "o.billing_street", "o.billing_city", "o.billing_state", "o.billing_zip", "o.billing_phone", "o.payment_type", "o.cardtype", "o.accountnumber", "o.status", "o.gateway", "o.gateway_environment", "o.payment_transaction_id", "o.subscription_transaction_id", "u.user_login", "u.user_email", "u.display_name", "l.name");
865
+
866
+ if($join_with_usermeta)
867
+ $fields[] = "um.meta_value";
868
+
869
+ $fields = apply_filters("pmpro_orders_search_fields", $fields);
870
+
871
+ foreach($fields as $field)
872
+ $sqlQuery .= " OR " . $field . " LIKE '%" . esc_sql($s) . "%' ";
873
+ $sqlQuery .= ") ";
874
+
875
+ $sqlQuery .= "AND " . $condition . " ";
876
+
877
+ $sqlQuery .= "GROUP BY o.id ORDER BY o.id DESC, o.timestamp DESC ";
878
+ }
879
+ else
880
+ {
881
+ $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS id FROM $wpdb->pmpro_membership_orders WHERE ".$condition." ORDER BY id DESC, timestamp DESC ";
882
+ }
883
+
884
+ $sqlQuery .= "LIMIT $start, $limit";
885
+
886
+ $order_ids = $wpdb->get_col($sqlQuery);
887
+
888
+ $totalrows = $wpdb->get_var("SELECT FOUND_ROWS() as found_rows");
889
+
890
+ if($order_ids)
891
+ {
892
+ ?>
893
+ <p class="clear"><?php printf(__("%d orders found.", "pmpro"), $totalrows);?></span></p>
894
+ <?php
895
+ }
896
+ ?>
897
+ <table class="widefat">
898
+ <thead>
899
+ <tr class="thead">
900
+ <th><?php _e('ID', 'pmpro');?></th>
901
+ <th><?php _e('Code', 'pmpro');?></th>
902
+ <th><?php _e('User', 'pmpro');?></th>
903
+ <?php do_action("pmpro_orders_extra_cols_header", $order_ids);?>
904
+ <th><?php _e('Membership Level', 'pmpro');?></th>
905
+ <th><?php _e('Total', 'pmpro');?></th>
906
+ <th><?php _e('Payment', 'pmpro');?></th>
907
+ <th><?php _e('Gateway', 'pmpro');?></th>
908
+ <th><?php _e('Transaction IDs', 'pmpro');?></th>
909
+ <th><?php _e('Status', 'pmpro');?></th>
910
+ <th><?php _e('Date', 'pmpro');?></th>
911
+ <th></th>
912
+ <th></th>
913
+ <th></th>
914
+ </tr>
915
+ </thead>
916
+ <tbody id="orders" class="list:order orders-list">
917
+ <?php
918
+ $count = 0;
919
+ foreach($order_ids as $order_id)
920
+ {
921
+ $order = new MemberOrder();
922
+ $order->nogateway = true;
923
+ $order->getMemberOrderByID($order_id);
924
+ ?>
925
+ <tr <?php if($count++ % 2 == 0) { ?>class="alternate"<?php } ?>>
926
+ <td><a href="admin.php?page=pmpro-orders&order=<?php echo $order->id?>"><?php echo $order->id;?></a></td>
927
+ <td><a href="admin.php?page=pmpro-orders&order=<?php echo $order->id?>"><?php echo $order->code;?></a></td>
928
+ <td>
929
+ <?php $order->getUser(); ?>
930
+ <?php if(!empty($order->user)) { ?>
931
+ <a href="user-edit.php?user_id=<?php echo $order->user->ID?>"><?php echo $order->user->user_login?></a>
932
+ <?php } else { ?>
933
+ [<?php _e('deleted', 'pmpro');?>]
934
+ <?php } ?>
935
+ </td>
936
+ <?php do_action("pmpro_orders_extra_cols_body", $order);?>
937
+ <td><?php echo $order->membership_id;?></td>
938
+ <td><?php echo pmpro_formatPrice($order->total);?></td>
939
+ <td>
940
+ <?php if(!empty($order->payment_type)) echo $order->payment_type . "<br />";?>
941
+ <?php if(!empty($order->accountnumber)) { ?>
942
+ <?php echo $order->cardtype;?>: x<?php echo last4($order->accountnumber);?><br />
943
+ <?php } ?>
944
+ <?php if(!empty($order->billing->street)) { ?>
945
+ <?php echo $order->billing->street; ?><br />
946
+ <?php if( $order->billing->city && $order->billing->state) { ?>
947
+ <?php echo $order->billing->city?>, <?php echo $order->billing->state?> <?php echo $order->billing->zip?> <?php if(!empty( $order->billing->country)) echo $order->billing->country?><br />
948
+ <?php } ?>
949
+ <?php } ?>
950
+ <?php if(!empty($order->billing->phone)) echo formatPhone($order->billing->phone);?>
951
+ </td>
952
+ <td><?php echo $order->gateway;?><?php if($order->gateway_environment == "test") echo "(test)";?></td>
953
+ <td>
954
+ <?php _e('Payment', 'pmpro');?>: <?php if(!empty($order->payment_transaction_id)) echo $order->payment_transaction_id; else echo "N/A";?>
955
+ <br />
956
+ <?php _e('Subscription', 'pmpro');?>: <?php if(!empty($order->subscription_transaction_id)) echo $order->subscription_transaction_id; else echo "N/A";?>
957
+ </td>
958
+ <td><?php echo $order->status;?></td>
959
+ <td><?php echo date(get_option('date_format'), $order->timestamp);?></td>
960
+ <td align="center">
961
+ <a href="admin.php?page=pmpro-orders&order=<?php echo $order->id;?>"><?php _e('edit', 'pmpro');?></a>
962
+ </td>
963
+ <td align="center">
964
+ <a href="admin.php?page=pmpro-orders&order=-1&copy=<?php echo $order->id;?>"><?php _e('copy', 'pmpro');?></a>
965
+ </td>
966
+ <td align="center">
967
+ <a href="javascript:askfirst('<?php printf(__("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>
968
+ </td>
969
+ </tr>
970
+ <?php
971
+ }
972
+
973
+ if(!$order_ids)
974
+ {
975
+ ?>
976
+ <tr>
977
+ <td colspan="9"><p><?php _e('No orders found.', 'pmpro');?></p></td>
978
+ </tr>
979
+ <?php
980
+ }
981
+ ?>
982
+ </tbody>
983
+ </table>
984
+ </form>
985
+
986
+ <?php
987
+ //add normal args
988
+ $pagination_url = add_query_arg($url_params, get_admin_url(NULL, "/admin.php?page=pmpro-orders"));
989
+ echo pmpro_getPaginationString($pn, $totalrows, $limit, 1, $pagination_url, "&limit=$limit&pn=");
990
+ ?>
991
+
992
+ <?php } ?>
993
+
994
+ <?php
995
+ require_once(dirname(__FILE__) . "/admin_footer.php");
996
+ ?>
adminpages/pagesettings.php ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //only admins can get this
3
+ if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_pagesettings")))
4
+ {
5
+ die(__("You do not have permissions to perform this action.", "pmpro"));
6
+ }
7
+
8
+ global $wpdb, $msg, $msgt;
9
+
10
+ //get/set settings
11
+ global $pmpro_pages;
12
+ if(!empty($_REQUEST['savesettings']))
13
+ {
14
+ //page ids
15
+ pmpro_setOption("account_page_id");
16
+ pmpro_setOption("billing_page_id");
17
+ pmpro_setOption("cancel_page_id");
18
+ pmpro_setOption("checkout_page_id");
19
+ pmpro_setOption("confirmation_page_id");
20
+ pmpro_setOption("invoice_page_id");
21
+ pmpro_setOption("levels_page_id");
22
+
23
+ //update the pages array
24
+ $pmpro_pages["account"] = pmpro_getOption("account_page_id");
25
+ $pmpro_pages["billing"] = pmpro_getOption("billing_page_id");
26
+ $pmpro_pages["cancel"] = pmpro_getOption("cancel_page_id");
27
+ $pmpro_pages["checkout"] = pmpro_getOption("checkout_page_id");
28
+ $pmpro_pages["confirmation"] = pmpro_getOption("confirmation_page_id");
29
+ $pmpro_pages["invoice"] = pmpro_getOption("invoice_page_id");
30
+ $pmpro_pages["levels"] = pmpro_getOption("levels_page_id");
31
+
32
+ //assume success
33
+ $msg = true;
34
+ $msgt = "Your page settings have been updated.";
35
+ }
36
+
37
+ //are we generating pages?
38
+ if(!empty($_REQUEST['createpages']))
39
+ {
40
+ global $pmpro_pages;
41
+
42
+ $pages_created = array();
43
+
44
+ //check the pages array
45
+ foreach($pmpro_pages as $pmpro_page_name => $pmpro_page_id)
46
+ {
47
+ if(!$pmpro_page_id)
48
+ {
49
+ switch ($pmpro_page_name) {
50
+ case 'account':
51
+ $pmpro_page_title = __( 'Membership Account', 'pmpro' );
52
+ break;
53
+ case 'billing':
54
+ $pmpro_page_title = __( 'Membership Billing', 'pmpro' );
55
+ break;
56
+ case 'cancel':
57
+ $pmpro_page_title = __( 'Membership Cancel', 'pmpro' );
58
+ break;
59
+ case 'checkout':
60
+ $pmpro_page_title = __( 'Membership Checkout', 'pmpro' );
61
+ break;
62
+ case 'confirmation':
63
+ $pmpro_page_title = __( 'Membership Confirmation', 'pmpro' );
64
+ break;
65
+ case 'invoice':
66
+ $pmpro_page_title = __( 'Membership Invoice', 'pmpro' );
67
+ break;
68
+ case 'levels':
69
+ $pmpro_page_title = __( 'Membership Levels', 'pmpro' );
70
+ break;
71
+
72
+ default:
73
+ $pmpro_page_title = sprintf( __( 'Membership %s', 'Page title template', 'pmpro' ), ucwords($pmpro_page_name) );
74
+ break;
75
+ }
76
+
77
+ //no id set. create an array to store the page info
78
+ $insert = array(
79
+ 'post_title' => $pmpro_page_title,
80
+ 'post_status' => 'publish',
81
+ 'post_type' => 'page',
82
+ 'post_content' => '[pmpro_' . $pmpro_page_name . ']',
83
+ 'comment_status' => 'closed',
84
+ 'ping_status' => 'closed'
85
+ );
86
+
87
+ //make non-account pages a subpage of account
88
+ if($pmpro_page_name != "account")
89
+ {
90
+ $insert['post_parent'] = $pmpro_pages['account'];
91
+ }
92
+
93
+ //create the page
94
+ $pmpro_pages[$pmpro_page_name] = wp_insert_post( $insert );
95
+
96
+ //add besecure post option to pages that need it
97
+ /* these pages are handling this themselves in the preheader
98
+ if(in_array($pmpro_page_name, array("billing", "checkout")))
99
+ update_post_meta($pmpro_pages[$pmpro_page_name], "besecure", 1);
100
+ */
101
+
102
+ //update the option too
103
+ pmpro_setOption($pmpro_page_name . "_page_id", $pmpro_pages[$pmpro_page_name]);
104
+ $pages_created[] = $pmpro_pages[$pmpro_page_name];
105
+ }
106
+ }
107
+
108
+ if(!empty($pages_created))
109
+ {
110
+ $msg = true;
111
+ $msgt = __("The following pages have been created for you", "pmpro") . ": " . implode(", ", $pages_created) . ".";
112
+ }
113
+ }
114
+
115
+ require_once(dirname(__FILE__) . "/admin_header.php");
116
+ ?>
117
+
118
+
119
+ <form action="" method="post" enctype="multipart/form-data">
120
+ <h2><?php _e('Pages', 'pmpro');?></h2>
121
+ <?php
122
+ global $pmpro_pages_ready;
123
+ if($pmpro_pages_ready)
124
+ {
125
+ ?>
126
+ <p><?php _e('Manage the WordPress pages assigned to each required Paid Memberships Pro page.', 'pmpro');?></p>
127
+ <?php
128
+ }
129
+ else
130
+ {
131
+ ?>
132
+ <p><?php _e('Assign the WordPress pages for each required Paid Memberships Pro page or', 'pmpro');?> <a href="?page=pmpro-pagesettings&createpages=1"><?php _e('click here to let us generate them for you', 'pmpro');?></a>.</p>
133
+ <?php
134
+ }
135
+ ?>
136
+ <table class="form-table">
137
+ <tbody>
138
+ <tr>
139
+ <th scope="row" valign="top">
140
+ <label for="account_page_id"><?php _e('Account Page', 'pmpro');?>:</label>
141
+ </th>
142
+ <td>
143
+ <?php
144
+ wp_dropdown_pages(array("name"=>"account_page_id", "show_option_none"=>"-- Choose One --", "selected"=>$pmpro_pages['account']));
145
+ ?>
146
+ <?php if(!empty($pmpro_pages['account'])) { ?>
147
+ <a target="_blank" href="post.php?post=<?php echo $pmpro_pages['account'];?>&action=edit" class="button button-secondary pmpro_page_edit"><?php _e('edit page', 'pmpro');?></a>
148
+ &nbsp;
149
+ <a target="_blank" href="<?php echo get_permalink($pmpro_pages['account']);?>" class="button button-secondary pmpro_page_view"><?php _e('view page', 'pmpro');?></a>
150
+ <?php } ?>
151
+ <br /><small class="pmpro_lite"><?php _e('Include the shortcode', 'pmpro');?> [pmpro_account].</small>
152
+ </td>
153
+ <tr>
154
+ <th scope="row" valign="top">
155
+ <label for="billing_page_id"><?php _e('Billing Information Page', 'pmpro');?>:</label>
156
+ </th>
157
+ <td>
158
+ <?php
159
+ wp_dropdown_pages(array("name"=>"billing_page_id", "show_option_none"=>"-- Choose One --", "selected"=>$pmpro_pages['billing']));
160
+ ?>
161
+ <?php if(!empty($pmpro_pages['billing'])) { ?>
162
+ <a target="_blank" href="post.php?post=<?php echo $pmpro_pages['billing']?>&action=edit" class="button button-secondary pmpro_page_edit"><?php _e('edit page', 'pmpro');?></a>
163
+ &nbsp;
164
+ <a target="_blank" href="<?php echo get_permalink($pmpro_pages['billing']);?>" class="button button-secondary pmpro_page_view"><?php _e('view page', 'pmpro');?></a>
165
+ <?php } ?>
166
+ <br /><small class="pmpro_lite"><?php _e('Include the shortcode', 'pmpro');?> [pmpro_billing].</small>
167
+ </td>
168
+ <tr>
169
+ <th scope="row" valign="top">
170
+ <label for="cancel_page_id"><?php _e('Cancel Page', 'pmpro');?>:</label>
171
+ </th>
172
+ <td>
173
+ <?php
174
+ wp_dropdown_pages(array("name"=>"cancel_page_id", "show_option_none"=>"-- Choose One --", "selected"=>$pmpro_pages['cancel']));
175
+ ?>
176
+ <?php if(!empty($pmpro_pages['cancel'])) { ?>
177
+ <a target="_blank" href="post.php?post=<?php echo $pmpro_pages['cancel']?>&action=edit" class="button button-secondary pmpro_page_edit"><?php _e('edit page', 'pmpro');?></a>
178
+ &nbsp;
179
+ <a target="_blank" href="<?php echo get_permalink($pmpro_pages['cancel']);?>" class="button button-secondary pmpro_page_view"><?php _e('view page', 'pmpro');?></a>
180
+ <?php } ?>
181
+ <br /><small class="pmpro_lite"><?php _e('Include the shortcode', 'pmpro');?> [pmpro_cancel].</small>
182
+ </td>
183
+ </tr>
184
+ <tr>
185
+ <th scope="row" valign="top">
186
+ <label for="checkout_page_id"><?php _e('Checkout Page', 'pmpro');?>:</label>
187
+ </th>
188
+ <td>
189
+ <?php
190
+ wp_dropdown_pages(array("name"=>"checkout_page_id", "show_option_none"=>"-- Choose One --", "selected"=>$pmpro_pages['checkout']));
191
+ ?>
192
+ <?php if(!empty($pmpro_pages['checkout'])) { ?>
193
+ <a target="_blank" href="post.php?post=<?php echo $pmpro_pages['checkout']?>&action=edit" class="button button-secondary pmpro_page_edit"><?php _e('edit page', 'pmpro');?></a>
194
+ &nbsp;
195
+ <a target="_blank" href="<?php echo get_permalink($pmpro_pages['checkout']);?>" class="button button-secondary pmpro_page_view"><?php _e('view page', 'pmpro');?></a>
196
+ <?php } ?>
197
+ <br /><small class="pmpro_lite"><?php _e('Include the shortcode', 'pmpro');?> [pmpro_checkout].</small>
198
+ </td>
199
+ </tr>
200
+ <tr>
201
+ <th scope="row" valign="top">
202
+ <label for="confirmation_page_id"><?php _e('Confirmation Page', 'pmpro');?>:</label>
203
+ </th>
204
+ <td>
205
+ <?php
206
+ wp_dropdown_pages(array("name"=>"confirmation_page_id", "show_option_none"=>"-- Choose One --", "selected"=>$pmpro_pages['confirmation']));
207
+ ?>
208
+ <?php if(!empty($pmpro_pages['confirmation'])) { ?>
209
+ <a target="_blank" href="post.php?post=<?php echo $pmpro_pages['confirmation']?>&action=edit" class="button button-secondary pmpro_page_edit"><?php _e('edit page', 'pmpro');?></a>
210
+ &nbsp;
211
+ <a target="_blank" href="<?php echo get_permalink($pmpro_pages['confirmation']);?>" class="button button-secondary pmpro_page_view"><?php _e('view page', 'pmpro');?></a>
212
+ <?php } ?>
213
+ <br /><small class="pmpro_lite"><?php _e('Include the shortcode', 'pmpro');?> [pmpro_confirmation].</small>
214
+ </td>
215
+ </tr>
216
+ <tr>
217
+ <th scope="row" valign="top">
218
+ <label for="invoice_page_id"><?php _e('Invoice Page', 'pmpro');?>:</label>
219
+ </th>
220
+ <td>
221
+ <?php
222
+ wp_dropdown_pages(array("name"=>"invoice_page_id", "show_option_none"=>"-- Choose One --", "selected"=>$pmpro_pages['invoice']));
223
+ ?>
224
+ <?php if(!empty($pmpro_pages['invoice'])) { ?>
225
+ <a target="_blank" href="post.php?post=<?php echo $pmpro_pages['invoice']?>&action=edit" class="button button-secondary pmpro_page_edit"><?php _e('edit page', 'pmpro');?></a>
226
+ &nbsp;
227
+ <a target="_blank" href="<?php echo get_permalink($pmpro_pages['invoice']);?>" class="button button-secondary pmpro_page_view"><?php _e('view page', 'pmpro');?></a>
228
+ <?php } ?>
229
+ <br /><small class="pmpro_lite"><?php _e('Include the shortcode', 'pmpro');?> [pmpro_invoice].</small>
230
+ </td>
231
+ </tr>
232
+ <tr>
233
+ <th scope="row" valign="top">
234
+ <label for="levels_page_id"><?php _e('Levels Page', 'pmpro');?>:</label>
235
+ </th>
236
+ <td>
237
+ <?php
238
+ wp_dropdown_pages(array("name"=>"levels_page_id", "show_option_none"=>"-- Choose One --", "selected"=>$pmpro_pages['levels']));
239
+ ?>
240
+ <?php if(!empty($pmpro_pages['levels'])) { ?>
241
+ <a target="_blank" href="post.php?post=<?php echo $pmpro_pages['levels']?>&action=edit" class="button button-secondary pmpro_page_edit"><?php _e('edit page', 'pmpro');?></a>
242
+ &nbsp;
243
+ <a target="_blank" href="<?php echo get_permalink($pmpro_pages['levels']);?>" class="button button-secondary pmpro_page_view"><?php _e('view page', 'pmpro');?></a>
244
+ <?php } ?>
245
+ <br /><small class="pmpro_lite"><?php _e('Include the shortcode', 'pmpro');?> [pmpro_levels].</small>
246
+ </td>
247
+ </tr>
248
+ </tbody>
249
+ </table>
250
+ <p class="submit">
251
+ <input name="savesettings" type="submit" class="button button-primary" value="<?php _e('Save Settings', 'pmpro');?>" />
252
+ </p>
253
+ </form>
254
+
255
+ <?php
256
+ require_once(dirname(__FILE__) . "/admin_footer.php");
257
+ ?>
adminpages/paymentsettings.php ADDED
@@ -0,0 +1,540 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //only admins can get this
3
+ if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_paymentsettings")))
4
+ {
5
+ die(__("You do not have permissions to perform this action.", "pmpro"));
6
+ }
7
+
8
+ global $wpdb, $pmpro_currency_symbol, $msg, $msgt;
9
+
10
+ //get/set settings
11
+ if(!empty($_REQUEST['savesettings']))
12
+ {
13
+ pmpro_setOption("sslseal");
14
+ pmpro_setOption("nuclear_HTTPS");
15
+
16
+ //gateway options
17
+ pmpro_setOption("gateway");
18
+ pmpro_setOption("gateway_environment");
19
+ pmpro_setOption("gateway_email");
20
+ pmpro_setOption("payflow_partner");
21
+ pmpro_setOption("payflow_vendor");
22
+ pmpro_setOption("payflow_user");
23
+ pmpro_setOption("payflow_pwd");
24
+ pmpro_setOption("apiusername");
25
+ pmpro_setOption("apipassword");
26
+ pmpro_setOption("apisignature");
27
+ pmpro_setOption("loginname");
28
+ pmpro_setOption("transactionkey");
29
+ pmpro_setOption("stripe_secretkey");
30
+ pmpro_setOption("stripe_publishablekey");
31
+ pmpro_setOption("stripe_billingaddress");
32
+ pmpro_setOption("braintree_merchantid");
33
+ pmpro_setOption("braintree_publickey");
34
+ pmpro_setOption("braintree_privatekey");
35
+ pmpro_setOption("braintree_encryptionkey");
36
+ pmpro_setOption("twocheckout_apiusername");
37
+ pmpro_setOption("twocheckout_apipassword");
38
+ pmpro_setOption("twocheckout_accountnumber");
39
+ pmpro_setOption("twocheckout_secretword");
40
+ pmpro_setOption("cybersource_merchantid");
41
+ pmpro_setOption("cybersource_securitykey");
42
+
43
+ //currency
44
+ pmpro_setOption("currency");
45
+
46
+ //credit cards
47
+ $pmpro_accepted_credit_cards = array();
48
+ if(!empty($_REQUEST['creditcards_visa']))
49
+ $pmpro_accepted_credit_cards[] = "Visa";
50
+ if(!empty($_REQUEST['creditcards_mastercard']))
51
+ $pmpro_accepted_credit_cards[] = "Mastercard";
52
+ if(!empty($_REQUEST['creditcards_amex']))
53
+ $pmpro_accepted_credit_cards[] = "American Express";
54
+ if(!empty($_REQUEST['creditcards_discover']))
55
+ $pmpro_accepted_credit_cards[] = "Discover";
56
+ if(!empty($_REQUEST['creditcards_dinersclub']))
57
+ $pmpro_accepted_credit_cards[] = "Diners Club";
58
+ if(!empty($_REQUEST['creditcards_enroute']))
59
+ $pmpro_accepted_credit_cards[] = "EnRoute";
60
+ if(!empty($_REQUEST['creditcards_jcb']))
61
+ $pmpro_accepted_credit_cards[] = "JCB";
62
+
63
+ //check instructions
64
+ pmpro_setOption("instructions");
65
+
66
+ //use_ssl
67
+ pmpro_setOption("use_ssl");
68
+
69
+ //tax
70
+ pmpro_setOption("tax_state");
71
+ pmpro_setOption("tax_rate");
72
+
73
+ pmpro_setOption("accepted_credit_cards", implode(",", $pmpro_accepted_credit_cards));
74
+
75
+ //assume success
76
+ $msg = true;
77
+ $msgt = __("Your payment settings have been updated.", "pmpro");
78
+ }
79
+
80
+ $sslseal = pmpro_getOption("sslseal");
81
+ $nuclear_HTTPS = pmpro_getOption("nuclear_HTTPS");
82
+
83
+ $gateway = pmpro_getOption("gateway");
84
+ $gateway_environment = pmpro_getOption("gateway_environment");
85
+ $gateway_email = pmpro_getOption("gateway_email");
86
+ $payflow_partner = pmpro_getOption("payflow_partner");
87
+ $payflow_vendor = pmpro_getOption("payflow_vendor");
88
+ $payflow_user = pmpro_getOption("payflow_user");
89
+ $payflow_pwd = pmpro_getOption("payflow_pwd");
90
+ $apiusername = pmpro_getOption("apiusername");
91
+ $apipassword = pmpro_getOption("apipassword");
92
+ $apisignature = pmpro_getOption("apisignature");
93
+ $loginname = pmpro_getOption("loginname");
94
+ $transactionkey = pmpro_getOption("transactionkey");
95
+ $stripe_secretkey = pmpro_getOption("stripe_secretkey");
96
+ $stripe_publishablekey = pmpro_getOption("stripe_publishablekey");
97
+ $stripe_billingaddress = pmpro_getOption("stripe_billingaddress");
98
+ $braintree_merchantid = pmpro_getOption("braintree_merchantid");
99
+ $braintree_publickey = pmpro_getOption("braintree_publickey");
100
+ $braintree_privatekey = pmpro_getOption("braintree_privatekey");
101
+ $braintree_encryptionkey = pmpro_getOption("braintree_encryptionkey");
102
+ $twocheckout_apiusername = pmpro_getOption("twocheckout_apiusername");
103
+ $twocheckout_apipassword = pmpro_getOption("twocheckout_apipassword");
104
+ $twocheckout_accountnumber = pmpro_getOption("twocheckout_accountnumber");
105
+ $twocheckout_secretword = pmpro_getOption("twocheckout_secretword");
106
+ $cybersource_merchantid = pmpro_getOption("cybersource_merchantid");
107
+ $cybersource_securitykey = pmpro_getOption("cybersource_securitykey");
108
+
109
+ $currency = pmpro_getOption("currency");
110
+
111
+ $pmpro_accepted_credit_cards = pmpro_getOption("accepted_credit_cards");
112
+
113
+ $instructions = pmpro_getOption("instructions");
114
+
115
+ $tax_state = pmpro_getOption("tax_state");
116
+ $tax_rate = pmpro_getOption("tax_rate");
117
+
118
+ //make sure the tax rate is not > 1
119
+ if((double)$tax_rate > 1)
120
+ {
121
+ //assume the entered X%
122
+ $tax_rate = $tax_rate / 100;
123
+ pmpro_setOption("tax_rate", $tax_rate);
124
+ }
125
+
126
+ $use_ssl = pmpro_getOption("use_ssl");
127
+
128
+ //default settings
129
+ if(empty($gateway_environment))
130
+ {
131
+ $gateway_environment = "sandbox";
132
+ pmpro_setOption("gateway_environment", $gateway_environment);
133
+ }
134
+ if(empty($pmpro_accepted_credit_cards))
135
+ {
136
+ $pmpro_accepted_credit_cards = "Visa,Mastercard,American Express,Discover";
137
+ pmpro_setOption("accepted_credit_cards", $pmpro_accepted_credit_cards);
138
+ }
139
+
140
+ $pmpro_accepted_credit_cards = explode(",", $pmpro_accepted_credit_cards);
141
+
142
+ require_once(dirname(__FILE__) . "/admin_header.php");
143
+ ?>
144
+
145
+ <form action="" method="post" enctype="multipart/form-data">
146
+ <h2><?php _e('Payment Gateway', 'pmpro');?> &amp; <?php _e('SSL Settings', 'pmpro');?></h2>
147
+
148
+ <p><?php _e('Learn more about <a title="Paid Memberships Pro - SSL Settings" target="_blank" href="http://www.paidmembershipspro.com/support/initial-plugin-setup/ssl/">SSL</a> or <a title="Paid Memberships Pro - Payment Gateway Settings" target="_blank" href="http://www.paidmembershipspro.com/support/initial-plugin-setup/payment-gateway/">Payment Gateway Settings</a>.', 'pmpro'); ?></p>
149
+
150
+ <table class="form-table">
151
+ <tbody>
152
+ <tr>
153
+ <th scope="row" valign="top">
154
+ <label for="gateway"><?php _e('Payment Gateway', 'pmpro');?>:</label>
155
+ </th>
156
+ <td>
157
+ <select id="gateway" name="gateway" onchange="pmpro_changeGateway(jQuery(this).val());">
158
+ <option value="">Testing Only</option>
159
+ <option value="check" <?php selected( $gateway, "check" ); ?>><?php _e('Pay by Check', 'pmpro');?></option>
160
+ <option value="stripe" <?php selected( $gateway, "stripe" ); ?>>Stripe</option>
161
+ <option value="paypalexpress" <?php selected( $gateway, "paypalexpress" ); ?>>PayPal Express</option>
162
+ <option value="paypal" <?php selected( $gateway, "paypal" ); ?>>PayPal Website Payments Pro</option>
163
+ <option value="payflowpro" <?php selected( $gateway, "payflowpro" ); ?>>PayPal Payflow Pro/PayPal Pro</option>
164
+ <option value="paypalstandard" <?php selected( $gateway, "paypalstandard" ); ?>>PayPal Standard</option>
165
+ <option value="authorizenet" <?php selected( $gateway, "authorizenet" ); ?>>Authorize.net</option>
166
+ <option value="braintree" <?php selected( $gateway, "braintree" ); ?>>Braintree Payments</option>
167
+ <option value="twocheckout" <?php selected( $gateway, "twocheckout" ); ?>>2Checkout</option>
168
+ <option value="cybersource" <?php selected( $gateway, "cybersource" ); ?>>CyberSource</option>
169
+ </select>
170
+ </td>
171
+ </tr>
172
+ <tr class="gateway gateway_cybersource gateway_twocheckout" <?php if($gateway != "cybersource" && $gateway != "twocheckout") { ?>style="display: none;"<?php } ?>>
173
+ <td colspan="2">
174
+ <strong><?php _e('Note', 'pmpro');?>:</strong> <?php _e('This gateway option is in beta. Some functionality may not be available. Please contact Paid Memberships Pro with any issues you run into. <strong>Please be sure to upgrade Paid Memberships Pro to the latest versions when available.</strong>', 'pmpro');?>
175
+ </td>
176
+ </tr>
177
+ <tr class="gateway gateway_paypalstandard" <?php if($gateway != "paypalstandard") { ?>style="display: none;"<?php } ?>>
178
+ <td colspan="2">
179
+ <strong><?php _e('Note', 'pmpro');?>:</strong> <?php _e('We do not recommend using PayPal Standard. We suggest using PayPal Express, Website Payments Pro (Legacy), or PayPal Pro (Payflow Pro). <a target="_blank" href="http://www.paidmembershipspro.com/2013/09/read-using-paypal-standard-paid-memberships-pro/">More information on why can be found here.</a>', 'pmpro');?>
180
+ </td>
181
+ </tr>
182
+ <tr>
183
+ <th scope="row" valign="top">
184
+ <label for="gateway_environment"><?php _e('Gateway Environment', 'pmpro');?>:</label>
185
+ </th>
186
+ <td>
187
+ <select name="gateway_environment">
188
+ <option value="sandbox" <?php selected( $gateway_environment, "sandbox" ); ?>><?php _e('Sandbox/Testing', 'pmpro');?></option>
189
+ <option value="live" <?php selected( $gateway_environment, "live" ); ?>><?php _e('Live/Production', 'pmpro');?></option>
190
+ </select>
191
+ <script>
192
+ function pmpro_changeGateway(gateway)
193
+ {
194
+ //hide all gateway options
195
+ jQuery('tr.gateway').hide();
196
+ jQuery('tr.gateway_'+gateway).show();
197
+ }
198
+ pmpro_changeGateway(jQuery('#gateway').val());
199
+ </script>
200
+ </td>
201
+ </tr>
202
+ <tr class="gateway gateway_payflowpro" <?php if($gateway != "payflowpro") { ?>style="display: none;"<?php } ?>>
203
+ <th scope="row" valign="top">
204
+ <label for="payflow_partner"><?php _e('Partner', 'pmpro');?>:</label>
205
+ </th>
206
+ <td>
207
+ <input type="text" id="payflow_partner" name="payflow_partner" size="60" value="<?php echo esc_attr($payflow_partner)?>" />
208
+ </td>
209
+ </tr>
210
+ <tr class="gateway gateway_payflowpro" <?php if($gateway != "payflowpro") { ?>style="display: none;"<?php } ?>>
211
+ <th scope="row" valign="top">
212
+ <label for="payflow_vendor"><?php _e('Vendor', 'pmpro');?>:</label>
213
+ </th>
214
+ <td>
215
+ <input type="text" id="payflow_vendor" name="payflow_vendor" size="60" value="<?php echo esc_attr($payflow_vendor)?>" />
216
+ </td>
217
+ </tr>
218
+ <tr class="gateway gateway_payflowpro" <?php if($gateway != "payflowpro") { ?>style="display: none;"<?php } ?>>
219
+ <th scope="row" valign="top">
220
+ <label for="payflow_user"><?php _e('User', 'pmpro');?>:</label>
221
+ </th>
222
+ <td>
223
+ <input type="text" id="payflow_user" name="payflow_user" size="60" value="<?php echo esc_attr($payflow_user)?>" />
224
+ </td>
225
+ </tr>
226
+ <tr class="gateway gateway_payflowpro" <?php if($gateway != "payflowpro") { ?>style="display: none;"<?php } ?>>
227
+ <th scope="row" valign="top">
228
+ <label for="payflow_pwd"><?php _e('Password', 'pmpro');?>:</label>
229
+ </th>
230
+ <td>
231
+ <input type="password" id="payflow_pwd" name="payflow_pwd" size="60" value="<?php echo esc_attr($payflow_pwd)?>" />
232
+ </td>
233
+ </tr>
234
+ <tr class="gateway gateway_paypal gateway_paypalexpress gateway_paypalstandard" <?php if($gateway != "paypal" && $gateway != "paypalexpress" && $gateway != "paypalstandard") { ?>style="display: none;"<?php } ?>>
235
+ <th scope="row" valign="top">
236
+ <label for="gateway_email"><?php _e('Gateway Account Email', 'pmpro');?>:</label>
237
+ </th>
238
+ <td>
239
+ <input type="text" id="gateway_email" name="gateway_email" size="60" value="<?php echo esc_attr($gateway_email)?>" />
240
+ </td>
241
+ </tr>
242
+ <tr class="gateway gateway_paypal gateway_paypalexpress" <?php if($gateway != "paypal" && $gateway != "paypalexpress") { ?>style="display: none;"<?php } ?>>
243
+ <th scope="row" valign="top">
244
+ <label for="apiusername"><?php _e('API Username', 'pmpro');?>:</label>
245
+ </th>
246
+ <td>
247
+ <input type="text" id="apiusername" name="apiusername" size="60" value="<?php echo esc_attr($apiusername)?>" />
248
+ </td>
249
+ </tr>
250
+ <tr class="gateway gateway_paypal gateway_paypalexpress" <?php if($gateway != "paypal" && $gateway != "paypalexpress") { ?>style="display: none;"<?php } ?>>
251
+ <th scope="row" valign="top">
252
+ <label for="apipassword"><?php _e('API Password', 'pmpro');?>:</label>
253
+ </th>
254
+ <td>
255
+ <input type="text" id="apipassword" name="apipassword" size="60" value="<?php echo esc_attr($apipassword)?>" />
256
+ </td>
257
+ </tr>
258
+ <tr class="gateway gateway_paypal gateway_paypalexpress" <?php if($gateway != "paypal" && $gateway != "paypalexpress") { ?>style="display: none;"<?php } ?>>
259
+ <th scope="row" valign="top">
260
+ <label for="apisignature"><?php _e('API Signature', 'pmpro');?>:</label>
261
+ </th>
262
+ <td>
263
+ <input type="text" id="apisignature" name="apisignature" size="60" value="<?php echo esc_attr($apisignature)?>" />
264
+ </td>
265
+ </tr>
266
+
267
+ <tr class="gateway gateway_authorizenet" <?php if($gateway != "authorizenet") { ?>style="display: none;"<?php } ?>>
268
+ <th scope="row" valign="top">
269
+ <label for="loginname"><?php _e('Login Name', 'pmpro');?>:</label>
270
+ </th>
271
+ <td>
272
+ <input type="text" id="loginname" name="loginname" size="60" value="<?php echo esc_attr($loginname)?>" />
273
+ </td>
274
+ </tr>
275
+ <tr class="gateway gateway_authorizenet" <?php if($gateway != "authorizenet") { ?>style="display: none;"<?php } ?>>
276
+ <th scope="row" valign="top">
277
+ <label for="transactionkey"><?php _e('Transaction Key', 'pmpro');?>:</label>
278
+ </th>
279
+ <td>
280
+ <input type="text" id="transactionkey" name="transactionkey" size="60" value="<?php echo esc_attr($transactionkey)?>" />
281
+ </td>
282
+ </tr>
283
+
284
+ <tr class="gateway gateway_stripe" <?php if($gateway != "stripe") { ?>style="display: none;"<?php } ?>>
285
+ <th scope="row" valign="top">
286
+ <label for="stripe_secretkey"><?php _e('Secret Key', 'pmpro');?>:</label>
287
+ </th>
288
+ <td>
289
+ <input type="text" id="stripe_secretkey" name="stripe_secretkey" size="60" value="<?php echo esc_attr($stripe_secretkey)?>" />
290
+ </td>
291
+ </tr>
292
+ <tr class="gateway gateway_stripe" <?php if($gateway != "stripe") { ?>style="display: none;"<?php } ?>>
293
+ <th scope="row" valign="top">
294
+ <label for="stripe_publishablekey"><?php _e('Publishable Key', 'pmpro');?>:</label>
295
+ </th>
296
+ <td>
297
+ <input type="text" id="stripe_publishablekey" name="stripe_publishablekey" size="60" value="<?php echo esc_attr($stripe_publishablekey)?>" />
298
+ </td>
299
+ </tr>
300
+
301
+ <tr class="gateway gateway_braintree" <?php if($gateway != "braintree") { ?>style="display: none;"<?php } ?>>
302
+ <th scope="row" valign="top">
303
+ <label for="braintree_merchantid"><?php _e('Merchant ID', 'pmpro');?>:</label>
304
+ </th>
305
+ <td>
306
+ <input type="text" id="braintree_merchantid" name="braintree_merchantid" size="60" value="<?php echo esc_attr($braintree_merchantid)?>" />
307
+ </td>
308
+ </tr>
309
+ <tr class="gateway gateway_braintree" <?php if($gateway != "braintree") { ?>style="display: none;"<?php } ?>>
310
+ <th scope="row" valign="top">
311
+ <label for="braintree_publickey"><?php _e('Public Key', 'pmpro');?>:</label>
312
+ </th>
313
+ <td>
314
+ <input type="text" id="braintree_publickey" name="braintree_publickey" size="60" value="<?php echo esc_attr($braintree_publickey)?>" />
315
+ </td>
316
+ </tr>
317
+ <tr class="gateway gateway_braintree" <?php if($gateway != "braintree") { ?>style="display: none;"<?php } ?>>
318
+ <th scope="row" valign="top">
319
+ <label for="braintree_privatekey"><?php _e('Private Key', 'pmpro');?>:</label>
320
+ </th>
321
+ <td>
322
+ <input type="text" id="braintree_privatekey" name="braintree_privatekey" size="60" value="<?php echo esc_attr($braintree_privatekey)?>" />
323
+ </td>
324
+ </tr>
325
+ <tr class="gateway gateway_braintree" <?php if($gateway != "braintree") { ?>style="display: none;"<?php } ?>>
326
+ <th scope="row" valign="top">
327
+ <label for="braintree_encryptionkey"><?php _e('Client-Side Encryption Key', 'pmpro');?>:</label>
328
+ </th>
329
+ <td>
330
+ <textarea id="braintree_encryptionkey" name="braintree_encryptionkey" rows="3" cols="80"><?php echo esc_textarea($braintree_encryptionkey)?></textarea>
331
+ </td>
332
+ </tr>
333
+
334
+ <tr class="gateway gateway_twocheckout" <?php if($gateway != "twocheckout") { ?>style="display: none;"<?php } ?>>
335
+ <th scope="row" valign="top">
336
+ <label for="twocheckout_apiusername"><?php _e('API Username', 'pmpro');?>:</label>
337
+ </th>
338
+ <td>
339
+ <input type="text" id="twocheckout_apiusername" name="twocheckout_apiusername" size="60" value="<?php echo esc_attr($twocheckout_apiusername)?>" />
340
+ </td>
341
+ </tr>
342
+ <tr class="gateway gateway_twocheckout" <?php if($gateway != "twocheckout") { ?>style="display: none;"<?php } ?>>
343
+ <th scope="row" valign="top">
344
+ <label for="twocheckout_apipassword"><?php _e('API Password', 'pmpro');?>:</label>
345
+ </th>
346
+ <td>
347
+ <input type="text" id="twocheckout_apipassword" name="twocheckout_apipassword" size="60" value="<?php echo esc_attr($twocheckout_apipassword)?>" />
348
+ </td>
349
+ </tr>
350
+ <tr class="gateway gateway_twocheckout" <?php if($gateway != "twocheckout") { ?>style="display: none;"<?php } ?>>
351
+ <th scope="row" valign="top">
352
+ <label for="twocheckout_accountnumber"><?php _e('Account Number', 'pmpro');?>:</label>
353
+ </th>
354
+ <td>
355
+ <input type="text" name="twocheckout_accountnumber" size="60" value="<?php echo $twocheckout_accountnumber?>" />
356
+ </td>
357
+ </tr>
358
+ <tr class="gateway gateway_twocheckout" <?php if($gateway != "twocheckout") { ?>style="display: none;"<?php } ?>>
359
+ <th scope="row" valign="top">
360
+ <label for="twocheckout_secretword"><?php _e('Secret Word', 'pmpro');?>:</label>
361
+ </th>
362
+ <td>
363
+ <input type="text" name="twocheckout_secretword" size="60" value="<?php echo $twocheckout_secretword?>" />
364
+ </td>
365
+ </tr>
366
+
367
+ <tr class="gateway gateway_cybersource" <?php if($gateway != "cybersource") { ?>style="display: none;"<?php } ?>>
368
+ <th scope="row" valign="top">
369
+ <label for="cybersource_merchantid"><?php _e('Merchant ID', 'pmpro');?>:</label>
370
+ </th>
371
+ <td>
372
+ <input type="text" id="cybersource_merchantid" name="cybersource_merchantid" size="60" value="<?php echo esc_attr($cybersource_merchantid)?>" />
373
+ </td>
374
+ </tr>
375
+ <tr class="gateway gateway_cybersource" <?php if($gateway != "cybersource") { ?>style="display: none;"<?php } ?>>
376
+ <th scope="row" valign="top">
377
+ <label for="cybersource_securitykey"><?php _e('Transaction Security Key', 'pmpro');?>:</label>
378
+ </th>
379
+ <td>
380
+ <textarea id="cybersource_securitykey" name="cybersource_securitykey" rows="3" cols="80"><?php echo esc_textarea($cybersource_securitykey);?></textarea>
381
+ </td>
382
+ </tr>
383
+
384
+ <tr class="gateway gateway_ gateway_paypal gateway_paypalexpress gateway_paypalstandard gateway_braintree gateway_twocheckout gateway_cybersource gateway_stripe gateway_authorizenet gateway_payflowpro gateway_check" <?php if(!empty($gateway) && $gateway != "paypal" && $gateway != "paypalexpress" && $gateway != "paypalstandard" && $gateway != "braintree" && $gateway != "twocheckout" && $gateway != "cybersource" && $gateway != "payflowpro" && $gateway != "stripe" && $gateway != "authorizenet") { ?>style="display: none;"<?php } ?>>
385
+ <th scope="row" valign="top">
386
+ <label for="currency"><?php _e('Currency', 'pmpro');?>:</label>
387
+ </th>
388
+ <td>
389
+ <select name="currency">
390
+ <?php
391
+ global $pmpro_currencies;
392
+ foreach($pmpro_currencies as $ccode => $cdescription)
393
+ {
394
+ if(is_array($cdescription))
395
+ $cdescription = $cdescription['name'];
396
+ ?>
397
+ <option value="<?php echo $ccode?>" <?php if($currency == $ccode) { ?>selected="selected"<?php } ?>><?php echo $cdescription?></option>
398
+ <?php
399
+ }
400
+ ?>
401
+ </select>
402
+ <small><?php _e( 'Not all currencies will be supported by every gateway. Please check with your gateway.', 'pmpro' ); ?></small>
403
+ </td>
404
+ </tr>
405
+
406
+ <tr class="gateway gateway_ gateway_stripe gateway_authorizenet gateway_paypal gateway_payflowpro gateway_braintree gateway_twocheckout gateway_cybersource" <?php if(!empty($gateway) && $gateway != "authorizenet" && $gateway != "paypal" && $gateway != "stripe" && $gateway != "payflowpro" && $gateway != "braintree" && $gateway != "twocheckout" && $gateway != "cybersource") { ?>style="display: none;"<?php } ?>>
407
+ <th scope="row" valign="top">
408
+ <label for="creditcards"><?php _e('Accepted Credit Card Types', 'pmpro');?></label>
409
+ </th>
410
+ <td>
411
+ <input type="checkbox" name="creditcards_visa" value="1" <?php if(in_array("Visa", $pmpro_accepted_credit_cards)) { ?>checked="checked"<?php } ?> /> Visa<br />
412
+ <input type="checkbox" name="creditcards_mastercard" value="1" <?php if(in_array("Mastercard", $pmpro_accepted_credit_cards)) { ?>checked="checked"<?php } ?> /> Mastercard<br />
413
+ <input type="checkbox" name="creditcards_amex" value="1" <?php if(in_array("American Express", $pmpro_accepted_credit_cards)) { ?>checked="checked"<?php } ?> /> American Express<br />
414
+ <input type="checkbox" name="creditcards_discover" value="1" <?php if(in_array("Discover", $pmpro_accepted_credit_cards)) { ?>checked="checked"<?php } ?> /> Discover<br />
415
+ <input type="checkbox" name="creditcards_dinersclub" value="1" <?php if(in_array("Diners Club", $pmpro_accepted_credit_cards)) {?>checked="checked"<?php } ?> /> Diner's Club<br />
416
+ <input type="checkbox" name="creditcards_enroute" value="1" <?php if(in_array("EnRoute", $pmpro_accepted_credit_cards)) {?>checked="checked"<?php } ?> /> EnRoute<br />
417
+ <input type="checkbox" name="creditcards_jcb" value="1" <?php if(in_array("JCB", $pmpro_accepted_credit_cards)) {?>checked="checked"<?php } ?> /> JCB<br />
418
+ </td>
419
+ </tr>
420
+ <tr class="gateway gateway_check" <?php if($gateway != "check") { ?>style="display: none;"<?php } ?>>
421
+ <th scope="row" valign="top">
422
+ <label for="instructions"><?php _e('Instructions', 'pmpro');?></label>
423
+ </th>
424
+ <td>
425
+ <textarea id="instructions" name="instructions" rows="3" cols="80"><?php echo esc_textarea($instructions)?></textarea>
426
+ <p><small><?php _e('Who to write the check out to. Where to mail it. Shown on checkout, confirmation, and invoice pages.', 'pmpro');?></small></p>
427
+ </td>
428
+ </tr>
429
+
430
+ <tr class="gateway gateway_stripe" <?php if($gateway != "stripe") { ?>style="display: none;"<?php } ?>>
431
+ <th scope="row" valign="top">
432
+ <label for="stripe_billingaddress"><?php _e('Show Billing Address Fields', 'pmpro');?>:</label>
433
+ </th>
434
+ <td>
435
+ <select id="stripe_billingaddress" name="stripe_billingaddress">
436
+ <option value="0" <?php if(empty($stripe_billingaddress)) { ?>selected="selected"<?php } ?>><?php _e('No', 'pmpro');?></option>
437
+ <option value="1" <?php if(!empty($stripe_billingaddress)) { ?>selected="selected"<?php } ?>><?php _e('Yes', 'pmpro');?></option>
438
+ </select>
439
+ <small><?php _e("Stripe doesn't require billing address fields. Choose 'No' to hide them on the checkout page.<br /><strong>If No, make sure you disable address verification in the Stripe dashboard settings.</strong>", 'pmpro');?></small>
440
+ </td>
441
+ </tr>
442
+
443
+ <tr class="gateway gateway_ gateway_stripe gateway_authorizenet gateway_paypal gateway_paypalexpress gateway_check gateway_paypalstandard gateway_payflowpro gateway_braintree gateway_twocheckout gateway_cybersource" <?php if(!empty($gateway) && $gateway != "stripe" && $gateway != "authorizenet" && $gateway != "paypal" && $gateway != "paypalexpress" && $gateway != "check" && $gateway != "paypalstandard" && $gateway != "payflowpro" && $gateway != "braintree" && $gateway != "twocheckout" && $gateway != "cybersource") { ?>style="display: none;"<?php } ?>>
444
+ <th scope="row" valign="top">
445
+ <label for="tax"><?php _e('Sales Tax', 'pmpro');?> <small>(<?php _e('optional', 'pmpro');?>)</small></label>
446
+ </th>
447
+ <td>
448
+ <?php _e('Tax State', 'pmpro');?>:
449
+ <input type="text" id="tax_state" name="tax_state" size="4" value="<?php echo esc_attr($tax_state)?>" /> <small>(<?php _e('abbreviation, e.g. "PA"', 'pmpro');?>)</small>
450
+ &nbsp; Tax Rate:
451
+ <input type="text" id="tax_rate" name="tax_rate" size="10" value="<?php echo esc_attr($tax_rate)?>" /> <small>(<?php _e('decimal, e.g. "0.06"', 'pmpro');?>)</small>
452
+ <p><small><?php _e('US only. If values are given, tax will be applied for any members ordering from the selected state.<br />For non-US or more complex tax rules, use the <a target="_blank" href="http://www.paidmembershipspro.com/2013/10/non-us-taxes-paid-memberships-pro/">pmpro_tax filter</a>.', 'pmpro');?></small></p>
453
+ </td>
454
+ </tr>
455
+ <tr class="gateway gateway_ gateway_stripe gateway_paypalexpress gateway_check gateway_paypalstandard gateway_braintree gateway_twocheckout gateway_cybersource gateway_payflowpro gateway_authorizenet gateway_paypal">
456
+ <th scope="row" valign="top">
457
+ <label for="use_ssl"><?php _e('Force SSL', 'pmpro');?>:</label>
458
+ </th>
459
+ <td>
460
+ <select id="use_ssl" name="use_ssl">
461
+ <option value="0" <?php if(empty($use_ssl)) { ?>selected="selected"<?php } ?>><?php _e('No', 'pmpro');?></option>
462
+ <option value="1" <?php if(!empty($use_ssl) && $use_ssl == 1) { ?>selected="selected"<?php } ?>><?php _e('Yes', 'pmpro');?></option>
463
+ <option value="2" <?php if(!empty($use_ssl) && $use_ssl == 2) { ?>selected="selected"<?php } ?>><?php _e('Yes (with JavaScript redirects)', 'pmpro');?></option>
464
+ </select>
465
+ <small>Recommended: Yes. Try the JavaScript redirects setting if you are having issues with infinite redirect loops.</small>
466
+ </td>
467
+ </tr>
468
+ <tr>
469
+ <th scope="row" valign="top">
470
+ <label for="sslseal"><?php _e('SSL Seal Code', 'pmpro');?>:</label>
471
+ </th>
472
+ <td>
473
+ <textarea id="sslseal" name="sslseal" rows="3" cols="80"><?php echo stripslashes(esc_textarea($sslseal))?></textarea>
474
+ <br /><small>Your <strong><a target="_blank" href="http://www.paidmembershipspro.com/documentation/initial-plugin-setup/ssl/">SSL Certificate</a></strong> must be installed by your web host. Your <strong>SSL Seal</strong> will be a short HTML or JavaScript snippet that can be pasted here.</small>
475
+ </td>
476
+ </tr>
477
+ <tr>
478
+ <th scope="row" valign="top">
479
+ <label for="nuclear_HTTPS"><?php _e('HTTPS Nuclear Option', 'pmpro');?>:</label>
480
+ </th>
481
+ <td>
482
+ <input type="checkbox" id="nuclear_HTTPS" name="nuclear_HTTPS" value="1" <?php if(!empty($nuclear_HTTPS)) { ?>checked="checked"<?php } ?> /> <?php _e('Use the "Nuclear Option" to use secure (HTTPS) URLs on your secure pages. Check this if you are using SSL and have warnings on your checkout pages.', 'pmpro');?>
483
+ </td>
484
+ </tr>
485
+ <tr class="gateway gateway_paypal gateway_paypalexpress gateway_paypalstandard gateway_payflowpro" <?php if($gateway != "paypal" && $gateway != "paypalexpress" && $gateway != "paypalstandard" && $gateway != "payflowpro") { ?>style="display: none;"<?php } ?>>
486
+ <th scope="row" valign="top">
487
+ <label><?php _e('IPN Handler URL', 'pmpro');?>:</label>
488
+ </th>
489
+ <td>
490
+ <p><?php _e('To fully integrate with PayPal, be sure to set your IPN Handler URL to ', 'pmpro');?> <pre><?php echo admin_url("admin-ajax.php") . "?action=ipnhandler";?></pre></p>
491
+ </td>
492
+ </tr>
493
+ <tr class="gateway gateway_twocheckout" <?php if($gateway != "twocheckout") { ?>style="display: none;"<?php } ?>>
494
+ <th scope="row" valign="top">
495
+ <label><?php _e('TwoCheckout INS URL', 'pmpro');?>:</label>
496
+ </th>
497
+ <td>
498
+ <p><?php _e('To fully integrate with 2Checkout, be sure to set your 2Checkout INS URL ', 'pmpro');?> <pre><?php echo admin_url("admin-ajax.php") . "?action=twocheckout-ins";?></pre></p>
499
+ </td>
500
+ </tr>
501
+ <tr class="gateway gateway_authorizenet" <?php if($gateway != "authorizenet") { ?>style="display: none;"<?php } ?>>
502
+ <th scope="row" valign="top">
503
+ <label><?php _e('Silent Post URL', 'pmpro');?>:</label>
504
+ </th>
505
+ <td>
506
+ <p><?php _e('To fully integrate with Authorize.net, be sure to set your Silent Post URL to', 'pmpro');?> <pre><?php echo admin_url("admin-ajax.php") . "?action=authnet_silent_post";?></pre></p>
507
+ </td>
508
+ </tr>
509
+ <tr class="gateway gateway_stripe" <?php if($gateway != "stripe") { ?>style="display: none;"<?php } ?>>
510
+ <th scope="row" valign="top">
511
+ <label><?php _e('Web Hook URL', 'pmpro');?>:</label>
512
+ </th>
513
+ <td>
514
+ <p><?php _e('To fully integrate with Stripe, be sure to set your Web Hook URL to', 'pmpro');?> <pre><?php echo admin_url("admin-ajax.php") . "?action=stripe_webhook";?></pre></p>
515
+ </td>
516
+ </tr>
517
+ <tr class="gateway gateway_braintree" <?php if($gateway != "braintree") { ?>style="display: none;"<?php } ?>>
518
+ <th scope="row" valign="top">
519
+ <label><?php _e('Web Hook URL', 'pmpro');?>:</label>
520
+ </th>
521
+ <td>
522
+ <p>
523
+ <?php _e('To fully integrate with Braintree, be sure to set your Web Hook URL to', 'pmpro');?>
524
+ <pre><?php
525
+ //echo admin_url("admin-ajax.php") . "?action=braintree_webhook";
526
+ echo PMPRO_URL . "/services/braintree-webhook.php";
527
+ ?></pre>.
528
+ </p>
529
+ </td>
530
+ </tr>
531
+ </tbody>
532
+ </table>
533
+ <p class="submit">
534
+ <input name="savesettings" type="submit" class="button-primary" value="<?php _e('Save Settings', 'pmpro');?>" />
535
+ </p>
536
+ </form>
537
+
538
+ <?php
539
+ require_once(dirname(__FILE__) . "/admin_footer.php");
540
+ ?>
adminpages/reports.php ADDED
@@ -0,0 +1,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 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 = $_REQUEST['report'];
58
+ call_user_func("pmpro_report_" . $report . "_page");
59
+ }
60
+
61
+ require_once(dirname(__FILE__) . "/admin_footer.php");
62
+ ?>
adminpages/reports/login.php ADDED
@@ -0,0 +1,412 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ PMPro Report
4
+ Title: Logins
5
+ Slug: login
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
+ $pmpro_reports['login'] = __('Visits, Views, and Logins', 'pmpro');
17
+
18
+ function pmpro_report_login_widget()
19
+ {
20
+ global $wpdb;
21
+ $visits = get_option("pmpro_visits", array("today"=>0, "thisday"=>date("Y-m-d"), "alltime"=>0, "month"=>0, "thismonth"=>date("n")));
22
+ $views = get_option("pmpro_views", array("today"=>0, "thisday"=>date("Y-m-d"), "alltime"=>0, "month"=>0, "thismonth"=>date("n")));
23
+ $logins = get_option("pmpro_logins", array("today"=>0, "thisday"=>date("Y-m-d"), "alltime"=>0, "month"=>0, "thismonth"=>date("n")));
24
+ ?>
25
+ <div style="width: 33%; float: left;">
26
+ <p><?php _e('Visits Today', 'pmpro')?>: <?php echo $visits['today'];?></p>
27
+ <p><?php _e('Visits This Month', 'pmpro')?>: <?php echo $visits['month'];?></p>
28
+ <p><?php _e('Visits All Time', 'pmpro')?>: <?php echo $visits['alltime'];?></p>
29
+ </div>
30
+ <div style="width: 33%; float: left;">
31
+ <p><?php _e('Views Today', 'pmpro')?>: <?php echo $views['today'];?></p>
32
+ <p><?php _e('Views This Month', 'pmpro')?>: <?php echo $views['month'];?></p>
33
+ <p><?php _e('Views All Time', 'pmpro')?>: <?php echo $views['alltime'];?></p>
34
+ </div>
35
+ <div style="width: 33%; float: left;">
36
+ <p><?php _e('Logins Today', 'pmpro')?>: <?php echo $logins['today'];?></p>
37
+ <p><?php _e('Logins This Month', 'pmpro')?>: <?php echo $logins['month'];?></p>
38
+ <p><?php _e('Logins All Time', 'pmpro')?>: <?php echo $logins['alltime'];?></p>
39
+ </div>
40
+ <div class="clear"></div>
41
+ <?php
42
+ }
43
+
44
+ function pmpro_report_login_page()
45
+ {
46
+ global $wpdb;
47
+
48
+ //vars
49
+ if(!empty($_REQUEST['s']))
50
+ $s = $_REQUEST['s'];
51
+ else
52
+ $s = "";
53
+
54
+ if(!empty($_REQUEST['l']))
55
+ $l = $_REQUEST['l'];
56
+ else
57
+ $l = "";
58
+ ?>
59
+ <form id="posts-filter" method="get" action="">
60
+ <h2>
61
+ <?php _e('Visits, Views, and Logins Report', 'pmpro');?>
62
+ </h2>
63
+ <ul class="subsubsub">
64
+ <li>
65
+ <?php _ex('Show', 'Dropdown label, e.g. Show All Users', 'pmpro')?> <select name="l" onchange="jQuery('#posts-filter').submit();">
66
+ <option value="" <?php if(!$l) { ?>selected="selected"<?php } ?>><?php _e('All Users', 'pmpro')?></option>
67
+ <option value="all" <?php if($l == "all") { ?>selected="selected"<?php } ?>><?php _e('All Levels', 'pmpro')?></option>
68
+ <?php
69
+ $levels = $wpdb->get_results("SELECT id, name FROM $wpdb->pmpro_membership_levels ORDER BY name");
70
+ foreach($levels as $level)
71
+ {
72
+ ?>
73
+ <option value="<?php echo $level->id?>" <?php if($l == $level->id) { ?>selected="selected"<?php } ?>><?php echo $level->name?></option>
74
+ <?php
75
+ }
76
+ ?>
77
+ </select>
78
+ </li>
79
+ </ul>
80
+ <p class="search-box">
81
+ <label class="hidden" for="post-search-input"><?php _ex('Search', 'Search form label', 'pmpro')?> <?php if(empty($l)) echo "Users"; else echo "Members";?>:</label>
82
+ <input type="hidden" name="page" value="pmpro-reports" />
83
+ <input type="hidden" name="report" value="login" />
84
+ <input id="post-search-input" type="text" value="<?php echo $s?>" name="s"/>
85
+ <input class="button" type="submit" value="Search Members"/>
86
+ </p>
87
+ <?php
88
+ //some vars for the search
89
+ if(isset($_REQUEST['pn']))
90
+ $pn = $_REQUEST['pn'];
91
+ else
92
+ $pn = 1;
93
+
94
+ if(isset($_REQUEST['limit']))
95
+ $limit = $_REQUEST['limit'];
96
+ else
97
+ $limit = 15;
98
+
99
+ $end = $pn * $limit;
100
+ $start = $end - $limit;
101
+
102
+ if($s)
103
+ {
104
+ $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, mu.membership_id, mu.initial_payment, mu.billing_amount, mu.cycle_period, mu.cycle_number, mu.billing_limit, mu.trial_amount, mu.trial_limit, UNIX_TIMESTAMP(mu.startdate) as startdate, UNIX_TIMESTAMP(mu.enddate) as enddate, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id AND mu.status = 'active' LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id WHERE (u.user_login LIKE '%$s%' OR u.user_email LIKE '%$s%' OR um.meta_value LIKE '%$s%') ";
105
+
106
+ if($l == "all")
107
+ $sqlQuery .= " AND mu.status = 'active' AND mu.membership_id > 0 ";
108
+ elseif($l)
109
+ $sqlQuery .= " AND mu.membership_id = '" . $l . "' ";
110
+
111
+ $sqlQuery .= "GROUP BY u.ID ORDER BY user_registered DESC LIMIT $start, $limit";
112
+ }
113
+ else
114
+ {
115
+ $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, mu.membership_id, mu.initial_payment, mu.billing_amount, mu.cycle_period, mu.cycle_number, mu.billing_limit, mu.trial_amount, mu.trial_limit, UNIX_TIMESTAMP(mu.startdate) as startdate, UNIX_TIMESTAMP(mu.enddate) as enddate, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id AND mu.status = 'active' LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id";
116
+ $sqlQuery .= " WHERE 1=1 ";
117
+
118
+ if($l == "all")
119
+ $sqlQuery .= " AND mu.membership_id > 0 AND mu.status = 'active' ";
120
+ elseif($l)
121
+ $sqlQuery .= " AND mu.membership_id = '" . $l . "' ";
122
+ $sqlQuery .= "GROUP BY u.ID ORDER BY user_registered DESC LIMIT $start, $limit";
123
+ }
124
+
125
+ $sqlQuery = apply_filters("pmpro_members_list_sql", $sqlQuery);
126
+
127
+ $theusers = $wpdb->get_results($sqlQuery);
128
+ $totalrows = $wpdb->get_var("SELECT FOUND_ROWS() as found_rows");
129
+
130
+ if($theusers)
131
+ {
132
+ ?>
133
+ <p class="clear"><?php echo strval($totalrows)?> <?php if(empty($l)) echo "users"; else echo "members";?> found.
134
+ <?php
135
+ }
136
+ ?>
137
+ <table class="widefat">
138
+ <thead>
139
+ <tr class="thead">
140
+ <th><?php _e('ID', 'pmpro')?></th>
141
+ <th><?php _e('User', 'pmpro')?></th>
142
+ <th><?php _e('Name', 'pmpro')?></th>
143
+ <th><?php _e('Membership', 'pmpro')?></th>
144
+ <th><?php _e('Joined', 'pmpro')?></th>
145
+ <th><?php _e('Expires', 'pmpro')?></th>
146
+ <th><?php _e('Last Visit', 'pmpro')?></th>
147
+ <th><?php _e('Visits This Month', 'pmpro')?></th>
148
+ <th><?php _e('Total Visits', 'pmpro')?></th>
149
+ <th><?php _e('Views This Month', 'pmpro')?></th>
150
+ <th><?php _e('Total Views', 'pmpro')?></th>
151
+ <th><?php _e('Last Login', 'pmpro')?></th>
152
+ <th><?php _e('Logins This Month', 'pmpro')?></th>
153
+ <th><?php _e('Total Logins', 'pmpro')?></th>
154
+ </tr>
155
+ </thead>
156
+ <tbody id="users" class="list:user user-list">
157
+ <?php
158
+ $count = 0;
159
+ foreach($theusers as $auser)
160
+ {
161
+ //get meta
162
+ $theuser = get_userdata($auser->ID);
163
+ $visits = get_user_meta($auser->ID, "pmpro_visits", true);
164
+ $views = get_user_meta($auser->ID, "pmpro_views", true);
165
+ $logins = get_user_meta($auser->ID, "pmpro_logins", true);
166
+ if(empty($logins))
167
+ $logins = array("last"=>"N/A", "month"=>"N/A", "alltime"=>"N/A");
168
+ ?>
169
+ <tr <?php if($count++ % 2 == 0) { ?>class="alternate"<?php } ?>>
170
+ <td><?php echo $theuser->ID?></td>
171
+ <td>
172
+ <?php echo get_avatar($theuser->ID, 32)?>
173
+ <strong>
174
+ <?php
175
+ $userlink = '<a href="user-edit.php?user_id=' . $theuser->ID . '">' . $theuser->user_login . '</a>';
176
+ $userlink = apply_filters("pmpro_members_list_user_link", $userlink, $theuser);
177
+ echo $userlink;
178
+ ?>
179
+ </strong>
180
+ </td>
181
+ <td>
182
+ <?php echo $theuser->display_name;?>
183
+ </td>
184
+ <td><?php echo $auser->membership?></td>
185
+ <td><?php echo date("m/d/Y", strtotime($theuser->user_registered, current_time("timestamp")))?></td>
186
+ <td>
187
+ <?php
188
+ if($auser->enddate)
189
+ echo date(get_option('date_format'), $auser->enddate);
190
+ else
191
+ echo "Never";
192
+ ?>
193
+ </td>
194
+ <td><?php if(!empty($visits['last'])) echo $visits['last'];?></td>
195
+ <td><?php if(!empty($visits['month'])) echo $visits['month'];?></td>
196
+ <td><?php if(!empty($visits['alltime'])) echo $visits['alltime'];?></td>
197
+ <td><?php if(!empty($visits['month'])) echo $views['month'];?></td>
198
+ <td><?php if(!empty($visits['alltime'])) echo $views['alltime'];?></td>
199
+ <td><?php if(!empty($visits['last'])) echo $logins['last'];?></td>
200
+ <td><?php if(!empty($visits['month'])) echo $logins['month'];?></td>
201
+ <td><?php if(!empty($visits['alltime'])) echo $logins['alltime'];?></td>
202
+ </tr>
203
+ <?php
204
+ }
205
+
206
+ if(!$theusers)
207
+ {
208
+ ?>
209
+ <tr>
210
+ <td colspan="9"><p><?php _e('No members found.', 'pmpro')?> <?php if($l) { ?><a href="?page=pmpro-memberslist&s=<?php echo $s?>"><?php _e('Search all levels', 'pmpro')?></a>.<?php } ?></p></td>
211
+ </tr>
212
+ <?php
213
+ }
214
+ ?>
215
+ </tbody>
216
+ </table>
217
+ </form>
218
+
219
+ <?php
220
+ echo pmpro_getPaginationString($pn, $totalrows, $limit, 1, get_admin_url(NULL, "/admin.php?page=pmpro-reports&report=login&s=" . urlencode($s)), "&l=$l&limit=$limit&pn=");
221
+ ?>
222
+ <?php
223
+ }
224
+
225
+ /*
226
+ Other code required for your reports. This file is loaded every time WP loads with PMPro enabled.
227
+ */
228
+
229
+ //track visits
230
+ function pmpro_report_login_wp_visits()
231
+ {
232
+ //don't track admin
233
+ if(is_admin())
234
+ return;
235
+
236
+ //only track logged in users
237
+ if(!is_user_logged_in())
238
+ return;
239
+
240
+ //check for cookie
241
+ if(!empty($_COOKIE['pmpro_visit']))
242
+ return;
243
+
244
+ //set cookie, then track
245
+ setcookie("pmpro_visit", "1", NULL, COOKIEPATH, COOKIE_DOMAIN, false);
246
+
247
+ global $current_user;
248
+ //track for user
249
+ if(!empty($current_user->ID))
250
+ {
251
+ $visits = $current_user->pmpro_visits;
252
+ if(empty($visits))
253
+ $visits = array("last"=>"N/A", "thisdate"=>NULL, "month"=>0, "thismonth"=>NULL, "alltime"=>0);
254
+
255
+ //track logins for user
256
+ $visits['last'] = date(get_option("date_format"));
257
+ $visits['alltime']++;
258
+ $thismonth = date("n");
259
+ if($thismonth == $visits['thismonth'])
260
+ $visits['month']++;
261
+ else
262
+ {
263
+ $visits['month'] = 1;
264
+ $visits['thismonth'] = $thismonth;
265
+ }
266
+
267
+ //update user data
268
+ update_user_meta($current_user->ID, "pmpro_visits", $visits);
269
+ }
270
+
271
+ //track for all
272
+ $visits = get_option("pmpro_visits");
273
+ if(empty($visits))
274
+ $visits = array("today"=>0, "thisdate"=>NULL, "month"=>0, "thismonth"=> NULL, "alltime"=>0);
275
+
276
+ $visits['alltime']++;
277
+ $thisdate = date("Y-d-m");
278
+ if($thisdate == $visits['thisdate'])
279
+ $visits['today']++;
280
+ else
281
+ {
282
+ $visits['today'] = 1;
283
+ $visits['thisdate'] = $thisdate;
284
+ }
285
+ if($thismonth == $visits['thismonth'])
286
+ $visits['month']++;
287
+ else
288
+ {
289
+ $visits['month'] = 1;
290
+ $visits['thismonth'] = $thismonth;
291
+ }
292
+
293
+ update_option("pmpro_visits", $visits);
294
+ }
295
+ add_action("wp", "pmpro_report_login_wp_visits");
296
+
297
+ //we want to clear the pmpro_visit cookie on login/logout
298
+ function pmpro_report_login_clear_visit_cookie()
299
+ {
300
+ if(isset($_COOKIE['pmpro_visit']))
301
+ unset($_COOKIE['pmpro_visit']);
302
+ }
303
+ add_action("wp_login", "pmpro_report_login_clear_visit_cookie");
304
+ add_action("wp_logout", "pmpro_report_login_clear_visit_cookie");
305
+
306
+ //track views
307
+ function pmpro_report_login_wp_views()
308
+ {
309
+ //don't track admin
310
+ if(is_admin())
311
+ return;
312
+
313
+ global $current_user;
314
+ //track for user
315
+ if(!empty($current_user->ID))
316
+ {
317
+ $views = $current_user->pmpro_views;
318
+ if(empty($views))
319
+ $views = array("last"=>"N/A", "month"=>0, "alltime"=>0);
320
+
321
+ //track logins for user
322
+ $views['last'] = date(get_option("date_format"));
323
+ $views['alltime']++;
324
+ $thismonth = date("n");
325
+ if(isset($views['thismonth']) && $thismonth == $views['thismonth'])
326
+ $views['month']++;
327
+ else
328
+ {
329
+ $views['month'] = 1;
330
+ $views['thismonth'] = $thismonth;
331
+ }
332
+
333
+ //update user data
334
+ update_user_meta($current_user->ID, "pmpro_views", $views);
335
+ }
336
+
337
+ //track for all
338
+ $views = get_option("pmpro_views");
339
+ if(empty($views))
340
+ $views = array("today"=>0, "thisdate"=> NULL, "month"=>0, "thismonth"=> NULL, "alltime"=>0);
341
+
342
+ $views['alltime']++;
343
+ $thisdate = date("Y-d-m");
344
+ if($thisdate == $views['thisdate'])
345
+ $views['today']++;
346
+ else
347
+ {
348
+ $views['today'] = 1;
349
+ $views['thisdate'] = $thisdate;
350
+ }
351
+ $thismonth = date("n");
352
+ if(isset($views['thismonth']) && $thismonth == $views['thismonth'])
353
+ $views['month']++;
354
+ else
355
+ {
356
+ $views['month'] = 1;
357
+ $views['thismonth'] = $thismonth;
358
+ }
359
+
360
+ update_option("pmpro_views", $views);
361
+ }
362
+ add_action("wp", "pmpro_report_login_wp_views");
363
+
364
+ //track logins
365
+ function pmpro_report_login_wp_login($user_login)
366
+ {
367
+ //get user data
368
+ $user = get_user_by("login", $user_login);
369
+ $logins = $user->pmpro_logins;
370
+ if(empty($logins))
371
+ $logins = array("last"=>"N/A", "thisdate"=>NULL, "month"=>0, "thismonth"=> NULL, "alltime"=>0);
372
+
373
+ //track logins for user
374
+ $logins['last'] = date(get_option("date_format"));
375
+ $logins['alltime']++;
376
+ $thismonth = date("n");
377
+ if($thismonth == $logins['thismonth'])
378
+ $logins['month']++;
379
+ else
380
+ {
381
+ $logins['month'] = 1;
382
+ $logins['thismonth'] = $thismonth;
383
+ }
384
+
385
+ //update user data
386
+ update_user_meta($user->ID, "pmpro_logins", $logins);
387
+
388
+ //track logins overall
389
+ $logins = get_option("pmpro_logins");
390
+ if(empty($logins))
391
+ $logins = array("today"=>0, "thisdate"=>NULL, "month"=>0, "thismonth"=>NULL, "alltime"=>0);
392
+
393
+ $logins['alltime']++;
394
+ $thisdate = date("Y-d-m");
395
+ if($thisdate == $logins['thisdate'])
396
+ $logins['today']++;
397
+ else
398
+ {
399
+ $logins['today'] = 1;
400
+ $logins['thisdate'] = $thisdate;
401
+ }
402
+ if($thismonth == $logins['thismonth'])
403
+ $logins['month']++;
404
+ else
405
+ {
406
+ $logins['month'] = 1;
407
+ $logins['thismonth'] = $thismonth;
408
+ }
409
+
410
+ update_option("pmpro_logins", $logins);
411
+ }
412
+ add_action("wp_login", "pmpro_report_login_wp_login");
adminpages/reports/memberships.php ADDED
@@ -0,0 +1,660 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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) . '-31';
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");
adminpages/reports/sales.php ADDED
@@ -0,0 +1,406 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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");
91
+
92
+ $thisyear = date("Y");
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) . '-31';
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");
324
+ elseif($period == "this month")
325
+ $startdate = date("Y-m") . "-01";
326
+ elseif($period == "this year")
327
+ $startdate = date("Y") . "-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");
367
+ elseif($period == "this month")
368
+ $startdate = date("Y-m") . "-01";
369
+ elseif($period == "this year")
370
+ $startdate = date("Y") . "-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");
classes/class.memberorder.php CHANGED
@@ -3,6 +3,10 @@
3
  {
4
  function MemberOrder($id = NULL)
5
  {
 
 
 
 
6
  if($id)
7
  {
8
  if(is_numeric($id))
@@ -12,7 +16,7 @@
12
  }
13
  else
14
  return true; //blank constructor
15
- }
16
 
17
  function getMemberOrderByID($id)
18
  {
@@ -25,24 +29,34 @@
25
  $dbobj = $wpdb->get_row("SELECT *, UNIX_TIMESTAMP(timestamp) + " . ($gmt_offset * 3600) . " as timestamp FROM $wpdb->pmpro_membership_orders WHERE id = '$id' LIMIT 1");
26
 
27
  if($dbobj)
28
- {
29
  $this->id = $dbobj->id;
30
  $this->code = $dbobj->code;
31
  $this->session_id = $dbobj->session_id;
32
  $this->user_id = $dbobj->user_id;
33
  $this->membership_id = $dbobj->membership_id;
34
- $this->paypal_token = $dbobj->paypal_token;
 
35
  $this->billing->name = $dbobj->billing_name;
36
  $this->billing->street = $dbobj->billing_street;
37
  $this->billing->city = $dbobj->billing_city;
38
  $this->billing->state = $dbobj->billing_state;
39
  $this->billing->zip = $dbobj->billing_zip;
 
40
  $this->billing->phone = $dbobj->billing_phone;
41
 
42
  //split up some values
43
  $nameparts = pnp_split_full_name($this->billing->name);
44
- $this->FirstName = $nameparts['fname'];
45
- $this->LastName = $nameparts['lname'];
 
 
 
 
 
 
 
 
46
  $this->Address1 = $this->billing->street;
47
 
48
  //get email from user_id
@@ -73,13 +87,45 @@
73
  $this->affiliate_id = $dbobj->affiliate_id;
74
  $this->affiliate_subid = $dbobj->affiliate_subid;
75
 
 
 
 
 
 
 
76
  return $this->id;
77
  }
78
  else
79
  return false; //didn't find it in the DB
80
  }
81
 
82
- function getLastMemberOrder($user_id = NULL)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  {
84
  global $current_user, $wpdb;
85
  if(!$user_id)
@@ -88,11 +134,26 @@
88
  if(!$user_id)
89
  return false;
90
 
91
- $id = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_orders WHERE user_id = '" . $user_id . "' ORDER BY timestamp DESC LIMIT 1");
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
  return $this->getMemberOrderByID($id);
94
  }
95
 
 
 
 
96
  function getMemberOrderByCode($code)
97
  {
98
  global $wpdb;
@@ -103,26 +164,113 @@
103
  return false;
104
  }
105
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  function getUser()
107
  {
108
  global $wpdb;
109
 
110
- if($this->user)
111
- return $this->invoice->user;
112
 
113
  $gmt_offset = get_option('gmt_offset');
114
  $this->user = $wpdb->get_row("SELECT *, UNIX_TIMESTAMP(user_registered) + " . ($gmt_offset * 3600) . " as user_registered FROM $wpdb->users WHERE ID = '" . $this->user_id . "' LIMIT 1");
115
  return $this->user;
116
  }
117
 
118
- function getMembershipLevel()
119
  {
120
  global $wpdb;
121
 
122
- if($this->membership_level)
123
  return $this->membership_level;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
125
- $this->membership_level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . $this->membership_id . "' LIMIT 1");
 
 
 
 
 
 
 
 
126
  return $this->membership_level;
127
  }
128
 
@@ -131,27 +279,40 @@
131
  //get options
132
  $tax_state = pmpro_getOption("tax_state");
133
  $tax_rate = pmpro_getOption("tax_rate");
134
-
 
 
 
135
  //calculate tax
136
  if($tax_state && $tax_rate)
137
  {
138
  //we have values, is this order in the tax state?
139
- if(trim(strtoupper($this->billing->state)) == trim(strtoupper($tax_state)))
140
- {
141
- //set values array for filter
142
- $values = array("price" => $price, "tax_state" => $tax_state, "tax_rate" => $tax_rate, "billing_state" => $this->billing->state, "billing_city" => $this->billing_city, "billing_zip" => $this->billing->zip, "billing_country" => $this->billing->country);
143
-
144
  //return value, pass through filter
145
- return apply_filters("pmpro_tax", round((float)$price * (float)$tax_rate, 2), $values);
146
  }
147
  }
148
 
149
- return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  }
151
 
152
  function getTax($force = false)
153
  {
154
- if($this->tax && !$force)
155
  return $this->tax;
156
 
157
  //reset
@@ -160,74 +321,206 @@
160
  return $this->tax;
161
  }
162
 
163
- function saveOrder()
164
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  global $current_user, $wpdb;
166
 
167
  //get a random code to use for the public ID
168
- if(!$this->code)
169
  $this->code = $this->getRandomCode();
170
 
171
  //figure out how much we charged
172
- $amount = $this->InitialPayment;
173
-
174
- //Todo: Make sure the session is started
175
-
 
 
 
176
  //Todo: Tax?!, Coupons, Certificates, affiliates
177
- $this->subtotal = $amount;
178
- $tax = $this->getTax(true);
 
 
 
 
 
 
179
 
180
- //Todo: Different Payment Types?
181
- $payment_type = "";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
 
183
  //build query
184
- $this->sqlQuery = "INSERT INTO $wpdb->pmpro_membership_orders
185
- (`code`, `session_id`, `user_id`, `membership_id`, `paypal_token`, `billing_name`, `billing_street`, `billing_city`, `billing_state`, `billing_zip`, `billing_phone`, `subtotal`, `tax`, `couponamount`, `certificate_id`, `certificateamount`, `total`, `payment_type`, `cardtype`, `accountnumber`, `expirationmonth`, `expirationyear`, `status`, `gateway`, `gateway_environment`, `payment_transaction_id`, `subscription_transaction_id`, `timestamp`, `affiliate_id`, `affiliate_subid`)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  VALUES('" . $this->code . "',
187
  '" . session_id() . "',
188
- '" . $this->user_id . "',
189
- '" . $this->membership_id . "',
190
- '" . $this->Token . "',
191
- '" . $wpdb->escape(trim($this->billing->name)) . "',
192
- '" . $wpdb->escape(trim($this->billing->street)) . "',
193
- '" . $wpdb->escape($this->billing->city) . "',
194
- '" . $wpdb->escape($this->billing->state) . "',
195
- '" . $wpdb->escape($this->billing->zip) . "',
 
196
  '" . cleanPhone($this->billing->phone) . "',
197
  '" . $amount . "',
198
  '" . $tax . "',
199
- '" . $coupon. "',
200
- '" . $certificate_id . "',
201
- '" . $certficate_amount . "',
202
- '" . ((float)$amount + (float)$tax) . "',
203
- '" . $payment_type . "',
204
  '" . $this->cardtype . "',
205
  '" . hideCardNumber($this->accountnumber, false) . "',
206
  '" . substr($this->ExpirationDate, 0, 2) . "',
207
  '" . substr($this->ExpirationDate, 2, 4) . "',
208
- '" . $this->status . "',
209
- '" . pmpro_getOption("gateway") . "',
210
- '" . pmpro_getOption("gateway_environment") . "',
211
- '" . $this->payment_transaction_id . "',
212
- '" . $this->subscription_transaction_id . "',
213
- now(),
214
- '" . $affiliate_id . "',
215
- '" . $affiliate_subid . "'
216
- )";
 
 
 
 
217
  if($wpdb->query($this->sqlQuery) !== false)
218
- return $this->getMemberOrderByID($wpdb->insert_id);
 
 
 
 
 
219
  else
 
220
  return false;
 
221
  }
222
 
223
  function getRandomCode()
224
  {
225
  global $wpdb;
226
 
227
- while(!$code)
228
  {
229
- $scramble = md5(AUTH_KEY . time() . SECURE_AUTH_KEY);
230
  $code = substr($scramble, 0, 10);
 
231
  $check = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_orders WHERE code = '$code' LIMIT 1");
232
  if($check || is_numeric($code))
233
  $code = NULL;
@@ -240,11 +533,11 @@
240
  {
241
  global $wpdb;
242
 
243
- if(!$this->id)
244
  return false;
245
 
246
  $this->status = $newstatus;
247
- $this->sqlQuery = "UPDATE $wpdb->pmpro_membership_orders SET status = '" . $wpdb->escape($newstatus) . "' WHERE id = '" . $this->id . "' LIMIT 1";
248
  if($wpdb->query($this->sqlQuery) !== false)
249
  return true;
250
  else
@@ -253,1072 +546,72 @@
253
 
254
  function process()
255
  {
256
- $gateway = pmpro_getOption("gateway");
257
- if($gateway == "paypal")
258
- {
259
- if(floatval($this->InitialPayment) == 0)
260
- {
261
- //auth first, then process
262
- $authorization_id = $this->authorizeWithPayPal();
263
- if($authorization_id)
264
- {
265
- $this->voidAuthorizationWithPayPal($authorization_id);
266
- $this->ProfileStartDate = date("Y-m-d", strtotime("+ 1 " . $this->BillingPeriod)) . "T0:0:0";
267
- return $this->processWithPayPal();
268
- }
269
- else
270
- {
271
- if(!$this->error)
272
- $this->error = "Unknown error: Authorization failed.";
273
- return false;
274
- }
275
- }
276
- else
277
- {
278
- //charge first payment
279
- if($this->chargeWithPayPal())
280
- {
281
- //setup recurring billing
282
- if(pmpro_isLevelRecurring($this->membership_level))
283
- {
284
- $this->ProfileStartDate = date("Y-m-d", strtotime("+ 1 " . $this->BillingPeriod)) . "T0:0:0";
285
- return $this->processWithPayPal();
286
- }
287
- else
288
- {
289
- //only a one time charge
290
- $this->status = "success"; //saved on checkout page
291
- return true;
292
- }
293
- }
294
- else
295
- {
296
- if(!$this->error)
297
- $this->error = "Unknown error: Payment failed.";
298
- return false;
299
- }
300
- }
301
- }
302
- elseif($gateway == "authorizenet")
303
- {
304
- if(floatval($this->InitialPayment) == 0)
305
- {
306
- //auth first, then process
307
- if($this->authorizeWithAuthorizeNet())
308
- {
309
- $this->ProfileStartDate = date("Y-m-d", strtotime("+ 1 " . $this->BillingPeriod)) . "T0:0:0";
310
- return $this->processWithAuthorizeNet();
311
- }
312
- else
313
- {
314
- if(!$this->error)
315
- $this->error = "Unknown error: Authorization failed.";
316
- return false;
317
- }
318
- }
319
- else
320
- {
321
- //charge first payment
322
- if($this->chargeWithAuthorizeNet())
323
- {
324
- //setup recurring billing
325
- if(pmpro_isLevelRecurring($this->membership_level))
326
- {
327
- $this->ProfileStartDate = date("Y-m-d", strtotime("+ 1 " . $this->BillingPeriod)) . "T0:0:0";
328
- return $this->processWithAuthorizeNet();
329
- }
330
- else
331
- {
332
- //only a one time charge
333
- $this->status = "success"; //saved on checkout page
334
- return true;
335
- }
336
- }
337
- else
338
- {
339
- if(!$this->error)
340
- $this->error = "Unknown error: Payment failed.";
341
- return false;
342
- }
343
- }
344
- }
345
- else
346
- {
347
- if(pmpro_isAdmin())
348
- $this->error = "You must <a href=\"" . home_url('/wp-admin/admin.php?page=pmpro-membershiplevels&view=payment') . "\">setup a Payment Gateway</a> before any payments will be processed.";
349
- else
350
- $this->error = "A Payment Gateway must be setup before any payments will be processed.";
351
- return false;
352
- }
353
  }
354
 
355
  function cancel()
356
- {
357
- $gateway = $this->gateway;
358
-
359
- //if no gateway specified for the order, assume it is the current gateway
360
- if(!$gateway)
361
- $gateway = pmpro_getOption("gateway");
362
-
363
- if($gateway == "paypal")
364
- return $this->cancelWithPayPal();
365
- elseif($gateway == "authorizenet")
366
- return $this->cancelWithAuthorizeNet();
367
- else
368
- return false;
369
- }
370
-
371
- function updateBilling()
372
- {
373
- $gateway = $this->gateway;
374
-
375
- //if no gateway specified for the order, assume it is the current gateway
376
- if(!$gateway)
377
- $gateway = pmpro_getOption("gateway");
378
-
379
- if($gateway == "paypal")
380
- return $this->updateWithPayPal();
381
- elseif($gateway == "authorizenet")
382
- return $this->updateWithAuthorizeNet();
383
- else
384
- return false;
385
- }
386
-
387
- /**
388
- * PAYPAL Function
389
- * Send HTTP POST Request
390
- *
391
- * @param string The API method name
392
- * @param string The POST Message fields in &name=value pair format
393
- * @return array Parsed HTTP Response body
394
- */
395
- function PPHttpPost($methodName_, $nvpStr_) {
396
- global $gateway_environment;
397
- $environment = $gateway_environment;
398
-
399
- $API_UserName = pmpro_getOption("apiusername");
400
- $API_Password = pmpro_getOption("apipassword");
401
- $API_Signature = pmpro_getOption("apisignature");
402
- $API_Endpoint = "https://api-3t.paypal.com/nvp";
403
- if("sandbox" === $environment || "beta-sandbox" === $environment) {
404
- $API_Endpoint = "https://api-3t.$environment.paypal.com/nvp";
405
- }
406
-
407
- $version = urlencode('51.0');
408
-
409
- // setting the curl parameters.
410
- $ch = curl_init();
411
- curl_setopt($ch, CURLOPT_URL, $API_Endpoint);
412
- curl_setopt($ch, CURLOPT_VERBOSE, 1);
413
-
414
- // turning off the server and peer verification(TrustManager Concept).
415
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
416
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
417
-
418
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
419
- curl_setopt($ch, CURLOPT_POST, 1);
420
-
421
- // NVPRequest for submitting to server
422
- $nvpreq = "METHOD=$methodName_&VERSION=$version&PWD=$API_Password&USER=$API_UserName&SIGNATURE=$API_Signature$nvpStr_";
423
-
424
- // setting the nvpreq as POST FIELD to curl
425
- curl_setopt($ch, CURLOPT_POSTFIELDS, $nvpreq);
426
-
427
- // getting response from server
428
- $httpResponse = curl_exec($ch);
429
-
430
- if(!$httpResponse) {
431
- exit("$methodName_ failed: ".curl_error($ch).'('.curl_errno($ch).')');
432
- }
433
-
434
- // Extract the RefundTransaction response details
435
- $httpResponseAr = explode("&", $httpResponse);
436
-
437
- $httpParsedResponseAr = array();
438
- foreach ($httpResponseAr as $i => $value) {
439
- $tmpAr = explode("=", $value);
440
- if(sizeof($tmpAr) > 1) {
441
- $httpParsedResponseAr[$tmpAr[0]] = $tmpAr[1];
442
- }
443
- }
444
-
445
- if((0 == sizeof($httpParsedResponseAr)) || !array_key_exists('ACK', $httpParsedResponseAr)) {
446
- exit("Invalid HTTP Response for POST request($nvpreq) to $API_Endpoint.");
447
- }
448
-
449
- return $httpParsedResponseAr;
450
- }
451
-
452
- function authorizeWithPayPal()
453
- {
454
- if(!$this->code)
455
- $this->code = $this->getRandomCode();
456
-
457
- //paypal profile stuff
458
- $nvpStr = "";
459
- if($this->Token)
460
- $nvpStr .= "&TOKEN=" . $this->Token;
461
- $nvpStr .="&AMT=1.00&CURRENCYCODE=USD";
462
- $nvpStr .= "&NOTIFYURL=" . urlencode(PMPRO_URL . "/services/ipnhandler.php");
463
- //$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $this->PaymentAmount;
464
-
465
- $nvpStr .= "&PAYMENTACTION=Authorization&IPADDRESS=" . $_SERVER['REMOTE_ADDR'] . "&INVNUM=" . $this->code;
466
-
467
- //credit card fields
468
- if($this->cardtype == "American Express")
469
- $cardtype = "Amex";
470
-
471
- if($this->cardtype)
472
- $nvpStr .= "&CREDITCARDTYPE=" . $cardtype . "&ACCT=" . $this->accountnumber . "&EXPDATE=" . $this->ExpirationDate . "&CVV2=" . $this->CVV2;
473
-
474
- //Maestro/Solo card fields. (Who uses these?) :)
475
- if($this->StartDate)
476
- $nvpStr .= "&STARTDATE=" . $this->StartDate . "&ISSUENUMBER=" . $this->IssueNumber;
477
-
478
- //billing address, etc
479
- if($this->Address1)
480
- {
481
- $nvpStr .= "&EMAIL=" . $this->Email . "&FIRSTNAME=" . $this->FirstName . "&LASTNAME=" . $this->LastName . "&STREET=" . $this->Address1;
482
-
483
- if($this->Address2)
484
- $nvpStr .= "&STREET2=" . $this->Address2;
485
-
486
- $nvpStr .= "&CITY=" . $this->billing->city . "&STATE=" . $this->billing->state . "&COUNTRYCODE=" . $this->billing->country . "&ZIP=" . $this->billing->zip . "&SHIPTOPHONENUM=" . $this->billing->phone;
487
- }
488
-
489
- $this->httpParsedResponseAr = $this->PPHttpPost('DoDirectPayment', $nvpStr);
490
-
491
- if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
492
- $this->authorization_id = $this->httpParsedResponseAr[TRANSACTIONID];
493
- $this->updateStatus("authorized");
494
- return $this->authorization_id;
495
- } else {
496
- $this->status = "error";
497
- $this->errorcode = $this->httpParsedResponseAr[L_ERRORCODE0];
498
- $this->error = urldecode($this->httpParsedResponseAr[L_LONGMESSAGE0]);
499
- $this->shorterror = urldecode($this->httpParsedResponseAr[L_SHORTMESSAGE0]);
500
- return false;
501
- }
502
- }
503
-
504
- function voidAuthorizationWithPayPal($authorization_id)
505
- {
506
- //paypal profile stuff
507
- $nvpStr="&AUTHORIZATIONID=" . $authorization_id . "&NOTE=Voiding an authorization for a recurring payment setup.";
508
-
509
- $this->httpParsedResponseAr = $this->PPHttpPost('DoVoid', $nvpStr);
510
-
511
- if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
512
- return true;
513
- } else {
514
- $this->status = "error";
515
- $this->errorcode = $this->httpParsedResponseAr[L_ERRORCODE0];
516
- $this->error = urldecode($this->httpParsedResponseAr[L_LONGMESSAGE0]);
517
- $this->shorterror = urldecode($this->httpParsedResponseAr[L_SHORTMESSAGE0]);
518
- return false;
519
- }
520
- }
521
-
522
- function chargeWithPayPal()
523
  {
524
- if(!$this->code)
525
- $this->code = $this->getRandomCode();
526
-
527
- //taxes on the amount
528
- $amount = $this->InitialPayment;
529
- $amount_tax = $this->getTaxForPrice($amount);
530
- $this->subtotal = $amount;
531
- $amount = round((float)$amount + (float)$amount_tax, 2);
532
-
533
- //paypal profile stuff
534
- $nvpStr = "";
535
- if($this->Token)
536
- $nvpStr .= "&TOKEN=" . $this->Token;
537
- $nvpStr .="&AMT=" . $amount . "&ITEMAMT=" . $this->InitialPayment . "&TAXAMT=" . $amount_tax . "&CURRENCYCODE=USD";
538
- $nvpStr .= "&NOTIFYURL=" . urlencode(PMPRO_URL . "/services/ipnhandler.php");
539
- //$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $this->PaymentAmount;
540
-
541
- $nvpStr .= "&PAYMENTACTION=Sale&IPADDRESS=" . $_SERVER['REMOTE_ADDR'] . "&INVNUM=" . $this->code;
542
-
543
- //credit card fields
544
- if($this->cardtype == "American Express")
545
- $cardtype = "Amex";
546
-
547
- if($this->cardtype)
548
- $nvpStr .= "&CREDITCARDTYPE=" . $cardtype . "&ACCT=" . $this->accountnumber . "&EXPDATE=" . $this->ExpirationDate . "&CVV2=" . $this->CVV2;
549
-
550
- //Maestro/Solo card fields. (Who uses these?) :)
551
- if($this->StartDate)
552
- $nvpStr .= "&STARTDATE=" . $this->StartDate . "&ISSUENUMBER=" . $this->IssueNumber;
553
-
554
- //billing address, etc
555
- if($this->Address1)
556
- {
557
- $nvpStr .= "&EMAIL=" . $this->Email . "&FIRSTNAME=" . $this->FirstName . "&LASTNAME=" . $this->LastName . "&STREET=" . $this->Address1;
558
-
559
- if($this->Address2)
560
- $nvpStr .= "&STREET2=" . $this->Address2;
561
-
562
- $nvpStr .= "&CITY=" . $this->billing->city . "&STATE=" . $this->billing->state . "&COUNTRYCODE=" . $this->billing->country . "&ZIP=" . $this->billing->zip . "&SHIPTOPHONENUM=" . $this->billing->phone;
563
- }
564
-
565
- $this->httpParsedResponseAr = $this->PPHttpPost('DoDirectPayment', $nvpStr);
566
-
567
- if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
568
- $this->payment_transaction_id = $this->httpParsedResponseAr[TRANSACTIONID];
569
- $this->updateStatus("firstpayment");
570
- return true;
571
- } else {
572
- $this->status = "error";
573
- $this->errorcode = $this->httpParsedResponseAr[L_ERRORCODE0];
574
- $this->error = urldecode($this->httpParsedResponseAr[L_LONGMESSAGE0]);
575
- $this->shorterror = urldecode($this->httpParsedResponseAr[L_SHORTMESSAGE0]);
576
- return false;
577
- }
578
- }
579
-
580
- function processWithPayPal()
581
- {
582
- if(!$this->code)
583
- $this->code = $this->getRandomCode();
584
-
585
- //taxes on the amount
586
- $amount = $this->PaymentAmount;
587
- $amount_tax = $this->getTaxForPrice($amount);
588
- $this->subtotal = $amount;
589
- $amount = round((float)$amount + (float)$amount_tax, 2);
590
-
591
- //paypal profile stuff
592
- $nvpStr = "";
593
- if($this->Token)
594
- $nvpStr .= "&TOKEN=" . $this->Token;
595
- $nvpStr .="&AMT=" . $this->PaymentAmount . "&TAXAMT=" . $amount_tax . "&CURRENCYCODE=USD" . "&PROFILESTARTDATE=" . $this->ProfileStartDate;
596
- $nvpStr .= "&BILLINGPERIOD=" . $this->BillingPeriod . "&BILLINGFREQUENCY=" . $this->BillingFrequency . "&AUTOBILLAMT=AddToNextBilling";
597
- $nvpStr .= "&DESC=" . $amount;
598
- $nvpStr .= "&NOTIFYURL=" . urlencode(PMPRO_URL . "/services/ipnhandler.php");
599
- //$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $this->PaymentAmount;
600
-
601
- //if billing cycles are defined
602
- if($this->TotalBillingCycles)
603
- $nvpStr .= "&TOTALBILLINGCYCLES=" . $this->TotalBillingCycles;
604
-
605
- //if a trial period is defined
606
- if($this->TrialBillingPeriod)
607
  {
608
- $trial_amount = $this->TrialAmount;
609
- $trial_tax = $this->getTaxForPrice($trial_amount);
610
- $trial_amount = round((float)$trial_amount + (float)$trial_tax, 2);
611
-
612
- $nvpStr .= "&TRIALBILLINGPERIOD=" . $this->TrialBillingPeriod . "&TRIALBILLINGFREQUENCY=" . $this->TrialBillingFrequency . "&TRIALAMNT=" . $trial_amount;
613
- }
614
- if($this->TrialBillingCycles)
615
- $nvpStr .= "&TRIALTOTALBILLINGCYCLES=" . $this->TrialBillingCycles;
616
-
617
- //credit card fields
618
- if($this->cardtype == "American Express")
619
- $cardtype = "Amex";
620
-
621
- if($this->cardtype)
622
- $nvpStr .= "&CREDITCARDTYPE=" . $cardtype . "&ACCT=" . $this->accountnumber . "&EXPDATE=" . $this->ExpirationDate . "&CVV2=" . $this->CVV2;
623
-
624
- //Maestro/Solo card fields. (Who uses these?) :)
625
- if($this->StartDate)
626
- $nvpStr .= "&STARTDATE=" . $this->StartDate . "&ISSUENUMBER=" . $this->IssueNumber;
627
-
628
- //billing address, etc
629
- if($this->Address1)
630
- {
631
- $nvpStr .= "&EMAIL=" . $this->Email . "&FIRSTNAME=" . $this->FirstName . "&LASTNAME=" . $this->LastName . "&STREET=" . $this->Address1;
632
-
633
- if($this->Address2)
634
- $nvpStr .= "&STREET2=" . $this->Address2;
635
-
636
- $nvpStr .= "&CITY=" . $this->billing->city . "&STATE=" . $this->billing->state . "&COUNTRYCODE=" . $this->billing->country . "&ZIP=" . $this->billing->zip . "&SHIPTOPHONENUM=" . $this->billing->phone;
637
- }
638
-
639
- $this->httpParsedResponseAr = $this->PPHttpPost('CreateRecurringPaymentsProfile', $nvpStr);
640
-
641
- if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
642
- $this->status = "success";
643
- $this->subscription_transaction_id = urldecode($this->httpParsedResponseAr[PROFILEID]);
644
  return true;
645
- //exit('CreateRecurringPaymentsProfile Completed Successfully: '.print_r($this->httpParsedResponseAr, true));
646
- } else {
647
- $this->status = "error";
648
- $this->errorcode = $this->httpParsedResponseAr[L_ERRORCODE0];
649
- $this->error = urldecode($this->httpParsedResponseAr[L_LONGMESSAGE0]);
650
- $this->shorterror = urldecode($this->httpParsedResponseAr[L_SHORTMESSAGE0]);
651
- return false;
652
- //exit('CreateRecurringPaymentsProfile failed: ' . print_r($httpParsedResponseAr, true));
653
- }
654
- }
655
-
656
- function cancelWithPayPal()
657
- {
658
- //paypal profile stuff
659
- $nvpStr = "";
660
- $nvpStr .= "&PROFILEID=" . $this->subscription_transaction_id . "&ACTION=Cancel&NOTE=User requested cancel.";
661
-
662
- $this->httpParsedResponseAr = $this->PPHttpPost('ManageRecurringPaymentsProfileStatus', $nvpStr);
663
-
664
- if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
665
- $this->status = "success";
666
- return true;
667
- //exit('CreateRecurringPaymentsProfile Completed Successfully: '.print_r($this->httpParsedResponseAr, true));
668
- } else {
669
- $this->status = "error";
670
- $this->errorcode = $this->httpParsedResponseAr[L_ERRORCODE0];
671
- $this->error = urldecode($this->httpParsedResponseAr[L_LONGMESSAGE0]);
672
- $this->shorterror = urldecode($this->httpParsedResponseAr[L_SHORTMESSAGE0]);
673
- return false;
674
- //exit('CreateRecurringPaymentsProfile failed: ' . print_r($httpParsedResponseAr, true));
675
- }
676
- }
677
-
678
- function updateWithPayPal()
679
- {
680
- //paypal profile stuff
681
- $nvpStr = "";
682
- $nvpStr .= "&PROFILEID=" . $this->subscription_transaction_id;
683
-
684
- //credit card fields
685
- if($this->cardtype)
686
- $nvpStr .= "&CREDITCARDTYPE=" . $this->cardtype . "&ACCT=" . $this->accountnumber . "&EXPDATE=" . $this->ExpirationDate . "&CVV2=" . $this->CVV2;
687
-
688
- //Maestro/Solo card fields. (Who uses these?) :)
689
- if($this->StartDate)
690
- $nvpStr .= "&STARTDATE=" . $this->StartDate . "&ISSUENUMBER=" . $this->IssueNumber;
691
-
692
- //billing address, etc
693
- if($this->Address1)
694
- {
695
- $nvpStr .= "&EMAIL=" . $this->Email . "&FIRSTNAME=" . $this->FirstName . "&LASTNAME=" . $this->LastName . "&STREET=" . $this->Address1;
696
-
697
- if($this->Address2)
698
- $nvpStr .= "&STREET2=" . $this->Address2;
699
-
700
- $nvpStr .= "&CITY=" . $this->billing->city . "&STATE=" . $this->billing->state . "&COUNTRYCODE=" . $this->billing->country . "&ZIP=" . $this->billing->zip;
701
- }
702
-
703
- $this->httpParsedResponseAr = $this->PPHttpPost('UpdateRecurringPaymentsProfile', $nvpStr);
704
-
705
- if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
706
- $this->status = "success";
707
- $this->subscription_transaction_id = urldecode($this->httpParsedResponseAr[PROFILEID]);
708
- return true;
709
- //exit('CreateRecurringPaymentsProfile Completed Successfully: '.print_r($this->httpParsedResponseAr, true));
710
- } else {
711
- $this->status = "error";
712
- $this->errorcode = $this->httpParsedResponseAr[L_ERRORCODE0];
713
- $this->error = urldecode($this->httpParsedResponseAr[L_LONGMESSAGE0]);
714
- $this->shorterror = urldecode($this->httpParsedResponseAr[L_SHORTMESSAGE0]);
715
- return false;
716
- //exit('CreateRecurringPaymentsProfile failed: ' . print_r($httpParsedResponseAr, true));
717
- }
718
- }
719
-
720
- //Authorize.net Function
721
- //function to send xml request via fsockopen
722
- function send_request_via_fsockopen($host,$path,$content)
723
- {
724
- $posturl = "ssl://" . $host;
725
- $header = "Host: $host\r\n";
726
- $header .= "User-Agent: PHP Script\r\n";
727
- $header .= "Content-Type: text/xml\r\n";
728
- $header .= "Content-Length: ".strlen($content)."\r\n";
729
- $header .= "Connection: close\r\n\r\n";
730
- $fp = fsockopen($posturl, 443, $errno, $errstr, 30);
731
- if (!$fp)
732
- {
733
- $response = false;
734
  }
735
  else
736
- {
737
- error_reporting(E_ERROR);
738
- fputs($fp, "POST $path HTTP/1.1\r\n");
739
- fputs($fp, $header.$content);
740
- fwrite($fp, $out);
741
- $response = "";
742
- while (!feof($fp))
743
  {
744
- $response = $response . fgets($fp, 128);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
745
  }
746
- fclose($fp);
747
- error_reporting(E_ALL ^ E_NOTICE);
748
  }
749
- return $response;
750
  }
751
-
752
- //Authorize.net Function
753
- //function to send xml request via curl
754
- function send_request_via_curl($host,$path,$content)
755
- {
756
- $posturl = "https://" . $host . $path;
757
- $ch = curl_init();
758
- curl_setopt($ch, CURLOPT_URL, $posturl);
759
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
760
- curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type: text/xml"));
761
- curl_setopt($ch, CURLOPT_HEADER, 1);
762
- curl_setopt($ch, CURLOPT_POSTFIELDS, $content);
763
- curl_setopt($ch, CURLOPT_POST, 1);
764
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
765
- $response = curl_exec($ch);
766
- return $response;
767
- }
768
-
769
-
770
- //Authorize.net Function
771
- //function to parse Authorize.net response
772
- function parse_return($content)
773
  {
774
- $refId = $this->substring_between($content,'<refId>','</refId>');
775
- $resultCode = $this->substring_between($content,'<resultCode>','</resultCode>');
776
- $code = $this->substring_between($content,'<code>','</code>');
777
- $text = $this->substring_between($content,'<text>','</text>');
778
- $subscriptionId = $this->substring_between($content,'<subscriptionId>','</subscriptionId>');
779
- return array ($refId, $resultCode, $code, $text, $subscriptionId);
780
- }
781
-
782
- //Authorize.net Function
783
- //helper function for parsing response
784
- function substring_between($haystack,$start,$end)
785
  {
786
- if (strpos($haystack,$start) === false || strpos($haystack,$end) === false)
787
- {
788
- return false;
789
- }
790
- else
791
- {
792
- $start_position = strpos($haystack,$start)+strlen($start);
793
- $end_position = strpos($haystack,$end);
794
- return substr($haystack,$start_position,$end_position-$start_position);
795
- }
796
  }
797
 
798
- //authorize just $1 to test credit card
799
- function authorizeWithAuthorizeNet()
800
  {
801
- if(!$this->code)
802
- $this->code = $this->getRandomCode();
803
-
804
- $gateway_environment = $this->gateway_environment;
805
- if(!$gateway_environment)
806
- $gateway_environment = pmpro_getOption("gateway_environment");
807
- if($gateway_environment == "live")
808
- $host = "secure.authorize.net";
809
- else
810
- $host = "test.authorize.net";
811
-
812
- $path = "/gateway/transact.dll";
813
- $post_url = "https://" . $host . $path;
814
-
815
- //what amount to authorize? just $1 to test
816
- $amount = "1.00";
817
-
818
- //combine address
819
- $address = $this->Address1;
820
- if($this->Address2)
821
- $address .= "\n" . $this->Address2;
822
-
823
- $post_values = array(
824
-
825
- // the API Login ID and Transaction Key must be replaced with valid values
826
- "x_login" => pmpro_getOption("loginname"),
827
- "x_tran_key" => pmpro_getOption("transactionkey"),
828
-
829
- "x_version" => "3.1",
830
- "x_delim_data" => "TRUE",
831
- "x_delim_char" => "|",
832
- "x_relay_response" => "FALSE",
833
-
834
- "x_type" => "AUTH_ONLY",
835
- "x_method" => "CC",
836
- "x_card_type" => $this->cardtype,
837
- "x_card_num" => $this->accountnumber,
838
- "x_exp_date" => $this->ExpirationDate,
839
- "x_card_code" => $this->CVV2,
840
-
841
- "x_amount" => $amount,
842
- "x_description" => $this->level->name . " Membership",
843
-
844
- "x_first_name" => $this->FirstName,
845
- "x_last_name" => $this->LastName,
846
- "x_address" => $address,
847
- "x_city" => $this->billing->city,
848
- "x_state" => $this->billing->state,
849
- "x_zip" => $this->billing->zip,
850
- "x_country" => $this->billing->country,
851
- "x_invoice_num" => $this->code
852
- // Additional fields can be added here as outlined in the AIM integration
853
- // guide at: http://developer.authorize.net
854
- );
855
-
856
- // This section takes the input fields and converts them to the proper format
857
- // for an http post. For example: "x_login=username&x_tran_key=a1B2c3D4"
858
- $post_string = "";
859
- foreach( $post_values as $key => $value )
860
- { $post_string .= "$key=" . urlencode( $value ) . "&"; }
861
- $post_string = rtrim( $post_string, "& " );
862
-
863
- //curl
864
- $request = curl_init($post_url); // initiate curl object
865
- curl_setopt($request, CURLOPT_HEADER, 0); // set to 0 to eliminate header info from response
866
- curl_setopt($request, CURLOPT_RETURNTRANSFER, 1); // Returns response data instead of TRUE(1)
867
- curl_setopt($request, CURLOPT_POSTFIELDS, $post_string); // use HTTP POST to send form data
868
- curl_setopt($request, CURLOPT_SSL_VERIFYPEER, FALSE); // uncomment this line if you get no gateway response.
869
- $post_response = curl_exec($request); // execute curl post and store results in $post_response
870
- // additional options may be required depending upon your server configuration
871
- // you can find documentation on curl options at http://www.php.net/curl_setopt
872
- curl_close ($request); // close curl object
873
-
874
- // This line takes the response and breaks it into an array using the specified delimiting character
875
- $response_array = explode($post_values["x_delim_char"],$post_response);
876
- if($response_array[0] == 1)
877
- {
878
- $this->payment_transaction_id = $response_array[4];
879
- $this->updateStatus("authorized");
880
- return true;
881
- }
882
- else
883
- {
884
- //$this->status = "error";
885
- $this->errorcode = $response_array[2];
886
- $this->error = $response_array[3];
887
- $this->shorterror = $response_array[3];
888
- return false;
889
- }
890
  }
891
 
892
- //charge first periods payment
893
- function chargeWithAuthorizeNet()
894
  {
895
- if(!$this->code)
896
- $this->code = $this->getRandomCode();
897
-
898
- $gateway_environment = $this->gateway_environment;
899
- if(!$gateway_environment)
900
- $gateway_environment = pmpro_getOption("gateway_environment");
901
- if($gateway_environment == "live")
902
- $host = "secure.authorize.net";
903
- else
904
- $host = "test.authorize.net";
905
-
906
- $path = "/gateway/transact.dll";
907
- $post_url = "https://" . $host . $path;
908
-
909
- //what amount to charge?
910
- $amount = $this->InitialPayment;
911
-
912
- //tax
913
- $this->subtotal = $amount;
914
- $tax = $this->getTax(true);
915
- $amount = round((float)$this->subtotal + (float)$tax, 2);
916
-
917
- //combine address
918
- $address = $this->Address1;
919
- if($this->Address2)
920
- $address .= "\n" . $this->Address2;
921
-
922
- $post_values = array(
923
-
924
- // the API Login ID and Transaction Key must be replaced with valid values
925
- "x_login" => pmpro_getOption("loginname"),
926
- "x_tran_key" => pmpro_getOption("transactionkey"),
927
-
928
- "x_version" => "3.1",
929
- "x_delim_data" => "TRUE",
930
- "x_delim_char" => "|",
931
- "x_relay_response" => "FALSE",
932
-
933
- "x_type" => "AUTH_CAPTURE",
934
- "x_method" => "CC",
935
- "x_card_type" => $this->cardtype,
936
- "x_card_num" => $this->accountnumber,
937
- "x_exp_date" => $this->ExpirationDate,
938
- "x_card_code" => $this->CVV2,
939
-
940
- "x_amount" => $amount,
941
- "x_tax" => $tax,
942
- "x_description" => $this->level->name . " Membership",
943
-
944
- "x_first_name" => $this->FirstName,
945
- "x_last_name" => $this->LastName,
946
- "x_address" => $address,
947
- "x_city" => $this->billing->city,
948
- "x_state" => $this->billing->state,
949
- "x_zip" => $this->billing->zip,
950
- "x_country" => $this->billing->country,
951
- "x_invoice_num" => $this->code
952
-
953
- // Additional fields can be added here as outlined in the AIM integration
954
- // guide at: http://developer.authorize.net
955
- );
956
-
957
- // This section takes the input fields and converts them to the proper format
958
- // for an http post. For example: "x_login=username&x_tran_key=a1B2c3D4"
959
- $post_string = "";
960
- foreach( $post_values as $key => $value )
961
- { $post_string .= "$key=" . urlencode( $value ) . "&"; }
962
- $post_string = rtrim( $post_string, "& " );
963
-
964
- //curl
965
- $request = curl_init($post_url); // initiate curl object
966
- curl_setopt($request, CURLOPT_HEADER, 0); // set to 0 to eliminate header info from response
967
- curl_setopt($request, CURLOPT_RETURNTRANSFER, 1); // Returns response data instead of TRUE(1)
968
- curl_setopt($request, CURLOPT_POSTFIELDS, $post_string); // use HTTP POST to send form data
969
- curl_setopt($request, CURLOPT_SSL_VERIFYPEER, FALSE); // uncomment this line if you get no gateway response.
970
- $post_response = curl_exec($request); // execute curl post and store results in $post_response
971
- // additional options may be required depending upon your server configuration
972
- // you can find documentation on curl options at http://www.php.net/curl_setopt
973
- curl_close ($request); // close curl object
974
-
975
- // This line takes the response and breaks it into an array using the specified delimiting character
976
- $response_array = explode($post_values["x_delim_char"],$post_response);
977
- if($response_array[0] == 1)
978
- {
979
- $this->payment_transaction_id = $response_array[4];
980
- $this->updateStatus("firstpayment");
981
- return true;
982
- }
983
- else
984
- {
985
- //$this->status = "error";
986
- $this->errorcode = $response_array[2];
987
- $this->error = $response_array[3];
988
- $this->shorterror = $response_array[3];
989
  return false;
990
- }
991
- }
992
-
993
- function processWithAuthorizeNet()
994
- {
995
- //define variables to send
996
-
997
- if(!$this->code)
998
- $this->code = $this->getRandomCode();
999
 
1000
- $gateway_environment = $this->gateway_environment;
1001
- if(!$gateway_environment)
1002
- $gateway_environment = pmpro_getOption("gateway_environment");
1003
- if($gateway_environment == "live")
1004
- $host = "api.authorize.net";
1005
- else
1006
- $host = "apitest.authorize.net";
1007
-
1008
- $path = "/xml/v1/request.api";
1009
-
1010
- $loginname = pmpro_getOption("loginname");
1011
- $transactionkey = pmpro_getOption("transactionkey");
1012
-
1013
- $amount = $this->PaymentAmount;
1014
- $refId = $this->code;
1015
- $name = $this->membership_name;
1016
- $length = (int)$this->BillingFrequency;
1017
-
1018
- if($this->BillingPeriod == "Month")
1019
- $unit = "months";
1020
- elseif($this->BillingPeriod == "Day")
1021
- $unit = "days";
1022
- elseif($this->BillingPeriod == "Year" && $this->BillingFrequency == 1)
1023
  {
1024
- $unit = "months";
1025
- $length = 12;
1026
  }
1027
  else
1028
- return false; //authorize.net only supports months and days
1029
-
1030
- $startDate = substr($this->ProfileStartDate, 0, 10);
1031
- $totalOccurrences = (int)$this->TotalBillingCycles;
1032
- if(!$totalOccurrences)
1033
- $totalOccurrences = 9999;
1034
- $trialOccurrences = (int)$this->TrialBillingCycles;
1035
- $trialAmount = $this->TrialAmount;
1036
-
1037
- //taxes
1038
- $amount_tax = $this->getTaxForPrice($amount);
1039
- $trial_tax = $this->getTaxForPrice($trialAmount);
1040
-
1041
- $this->subtotal = $amount;
1042
- $amount = round((float)$amount + (float)$amount_tax, 2);
1043
- $trialAmount = round((float)$trialAmount + (float)$trial_tax, 2);
1044
-
1045
- //authorize.net doesn't support different periods between trial and actual
1046
- if($this->TrialBillingPeriod && $this->TrialBillingPeriod != $this->BillingPeriod)
1047
  return false;
1048
-
1049
- $cardNumber = $this->accountnumber;
1050
- $expirationDate = $this->ExpirationDate_YdashM;
1051
- $cardCode = $this->CVV2;
1052
-
1053
- $firstName = $this->FirstName;
1054
- $lastName = $this->LastName;
1055
-
1056
- //do address stuff then?
1057
- $address = $this->Address1;
1058
- if($this->Address2)
1059
- $address .= "\n" . $this->Address2;
1060
- $city = $this->billing->city;
1061
- $state = $this->billing->state;
1062
- $zip = $this->billing->zip;
1063
- $country = $this->billing->country;
1064
-
1065
- //customer stuff
1066
- $customer_email = $this->Email;
1067
- $customer_phone = $this->billing->phone;
1068
-
1069
- //build xml to post
1070
- $content =
1071
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>" .
1072
- "<ARBCreateSubscriptionRequest xmlns=\"AnetApi/xml/v1/schema/AnetApiSchema.xsd\">" .
1073
- "<merchantAuthentication>".
1074
- "<name>" . $loginname . "</name>".
1075
- "<transactionKey>" . $transactionkey . "</transactionKey>".
1076
- "</merchantAuthentication>".
1077
- "<refId>" . $refId . "</refId>".
1078
- "<subscription>".
1079
- "<name>" . $name . "</name>".
1080
- "<paymentSchedule>".
1081
- "<interval>".
1082
- "<length>". $length ."</length>".
1083
- "<unit>". $unit ."</unit>".
1084
- "</interval>".
1085
- "<startDate>" . $startDate . "</startDate>".
1086
- "<totalOccurrences>". $totalOccurrences . "</totalOccurrences>";
1087
- if($trialOccurrences)
1088
- $content .=
1089
- "<trialOccurrences>". $trialOccurrences . "</trialOccurrences>";
1090
- $content .=
1091
- "</paymentSchedule>".
1092
- "<amount>". $amount ."</amount>";
1093
- if($trialOccurrences)
1094
- $content .=
1095
- "<trialAmount>" . $trialAmount . "</trialAmount>";
1096
- $content .=
1097
- "<payment>".
1098
- "<creditCard>".
1099
- "<cardNumber>" . $cardNumber . "</cardNumber>".
1100
- "<expirationDate>" . $expirationDate . "</expirationDate>".
1101
- "<cardCode>" . $cardCode . "</cardCode>".
1102
- "</creditCard>".
1103
- "</payment>".
1104
- "<order><invoiceNumber>" . $this->code . "</invoiceNumber></order>".
1105
- "<customer>".
1106
- "<email>". $customer_email . "</email>".
1107
- "<phoneNumber>". $customer_phone . "</phoneNumber>".
1108
- "</customer>".
1109
- "<billTo>".
1110
- "<firstName>". $firstName . "</firstName>".
1111
- "<lastName>" . $lastName . "</lastName>".
1112
- "<address>". $address . "</address>".
1113
- "<city>" . $city . "</city>".
1114
- "<state>". $state . "</state>".
1115
- "<zip>" . $zip . "</zip>".
1116
- "<country>". $country . "</country>".
1117
- "</billTo>".
1118
- "</subscription>".
1119
- "</ARBCreateSubscriptionRequest>";
1120
-
1121
- //send the xml via curl
1122
- $response = $this->send_request_via_curl($host,$path,$content);
1123
- //if curl is unavilable you can try using fsockopen
1124
- /*
1125
- $response = send_request_via_fsockopen($host,$path,$content);
1126
- */
1127
-
1128
-
1129
- if($response) {
1130
- list ($refId, $resultCode, $code, $text, $subscriptionId) = $this->parse_return($response);
1131
- if($resultCode == "Ok")
1132
- {
1133
- $this->status = "success"; //saved on checkout page
1134
- $this->subscription_transaction_id = $subscriptionId;
1135
- return true;
1136
- }
1137
- else
1138
- {
1139
- $this->status = "error";
1140
- $this->errorcode = $code;
1141
- $this->error = $text;
1142
- $this->shorterror = $text;
1143
- return false;
1144
- }
1145
- } else {
1146
- $this->status = "error";
1147
- $this->error = "Could not connect to Authorize.net";
1148
- $this->shorterror = "Could not connect to Authorize.net";
1149
- return false;
1150
- }
1151
- }
1152
-
1153
- function cancelWithAuthorizeNet()
1154
- {
1155
- //define variables to send
1156
- $subscriptionId = $this->subscription_transaction_id;
1157
- $loginname = pmpro_getOption("loginname");
1158
- $transactionkey = pmpro_getOption("transactionkey");
1159
-
1160
- $gateway_environment = $this->gateway_environment;
1161
- if(!$gateway_environment)
1162
- $gateway_environment = pmpro_getOption("gateway_environment");
1163
- if($gateway_environment == "live")
1164
- $host = "api.authorize.net";
1165
- else
1166
- $host = "apitest.authorize.net";
1167
-
1168
- $path = "/xml/v1/request.api";
1169
-
1170
- if(!$subscriptionId || !$loginname || !$transactionkey)
1171
- return false;
1172
-
1173
- //build xml to post
1174
- $content =
1175
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>".
1176
- "<ARBCancelSubscriptionRequest xmlns=\"AnetApi/xml/v1/schema/AnetApiSchema.xsd\">".
1177
- "<merchantAuthentication>".
1178
- "<name>" . $loginname . "</name>".
1179
- "<transactionKey>" . $transactionkey . "</transactionKey>".
1180
- "</merchantAuthentication>" .
1181
- "<subscriptionId>" . $subscriptionId . "</subscriptionId>".
1182
- "</ARBCancelSubscriptionRequest>";
1183
-
1184
- //send the xml via curl
1185
- $response = $this->send_request_via_curl($host,$path,$content);
1186
- //if curl is unavilable you can try using fsockopen
1187
- /*
1188
- $response = send_request_via_fsockopen($host,$path,$content);
1189
- */
1190
-
1191
- //if the connection and send worked $response holds the return from Authorize.net
1192
- if ($response)
1193
- {
1194
- list ($resultCode, $code, $text, $subscriptionId) = $this->parse_return($response);
1195
-
1196
- if($resultCode == "Ok" || $code == "Ok")
1197
- {
1198
- $this->updateStatus("cancelled");
1199
- return true;
1200
- }
1201
- else
1202
- {
1203
- //$this->status = "error";
1204
- $this->errorcode = $code;
1205
- $this->error = $text;
1206
- $this->shorterror = $text;
1207
- return false;
1208
- }
1209
- }
1210
- else
1211
- {
1212
- $this->status = "error";
1213
- $this->error = "Could not connect to Authorize.net";
1214
- $this->shorterror = "Could not connect to Authorize.net";
1215
- return false;
1216
- }
1217
- }
1218
-
1219
- function updateWithAuthorizeNet()
1220
- {
1221
- //define variables to send
1222
- $gateway_environment = $this->gateway_environment;
1223
- if(!$gateway_environment)
1224
- $gateway_environment = pmpro_getOption("gateway_environment");
1225
- if($gateway_environment == "live")
1226
- $host = "api.authorize.net";
1227
- else
1228
- $host = "apitest.authorize.net";
1229
-
1230
- $path = "/xml/v1/request.api";
1231
-
1232
- $loginname = pmpro_getOption("loginname");
1233
- $transactionkey = pmpro_getOption("transactionkey");
1234
-
1235
- $amount = $this->PaymentAmount;
1236
- $refId = $this->code;
1237
- $subscriptionId = $this->subscription_transaction_id;
1238
-
1239
- $cardNumber = $this->accountnumber;
1240
- $expirationDate = $this->ExpirationDate_YdashM;
1241
- $cardCode = $this->CVV2;
1242
-
1243
- $firstName = $this->FirstName;
1244
- $lastName = $this->LastName;
1245
-
1246
- //do address stuff then?
1247
- $address = $this->Address1;
1248
- if($this->Address2)
1249
- $address .= "\n" . $this->Address2;
1250
- $city = $this->billing->city;
1251
- $state = $this->billing->state;
1252
- $zip = $this->billing->zip;
1253
- $country = $this->billing->country;
1254
-
1255
- //customer stuff
1256
- $customer_email = $this->Email;
1257
- $customer_phone = $this->billing->phone;
1258
-
1259
- //build xml to post
1260
- $content =
1261
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>" .
1262
- "<ARBUpdateSubscriptionRequest xmlns=\"AnetApi/xml/v1/schema/AnetApiSchema.xsd\">".
1263
- "<merchantAuthentication>".
1264
- "<name>" . $loginname . "</name>".
1265
- "<transactionKey>" . $transactionkey . "</transactionKey>".
1266
- "</merchantAuthentication>".
1267
- "<refId>" . $refId . "</refId>".
1268
- "<subscriptionId>" . $subscriptionId . "</subscriptionId>".
1269
- "<subscription>".
1270
- "<payment>".
1271
- "<creditCard>".
1272
- "<cardNumber>" . $cardNumber . "</cardNumber>".
1273
- "<expirationDate>" . $expirationDate . "</expirationDate>".
1274
- "<cardCode>" . $cardCode . "</cardCode>".
1275
- "</creditCard>".
1276
- "</payment>".
1277
- "<customer>".
1278
- "<email>". $customer_email . "</email>".
1279
- "<phoneNumber>". formatPhone($customer_phone) . "</phoneNumber>".
1280
- "</customer>".
1281
- "<billTo>".
1282
- "<firstName>". $firstName . "</firstName>".
1283
- "<lastName>" . $lastName . "</lastName>".
1284
- "<address>". $address . "</address>".
1285
- "<city>" . $city . "</city>".
1286
- "<state>". $state . "</state>".
1287
- "<zip>" . $zip . "</zip>".
1288
- "<country>". $country . "</country>".
1289
- "</billTo>".
1290
- "</subscription>".
1291
- "</ARBUpdateSubscriptionRequest>";
1292
-
1293
- //send the xml via curl
1294
- $response = $this->send_request_via_curl($host,$path,$content);
1295
- //if curl is unavilable you can try using fsockopen
1296
- /*
1297
- $response = send_request_via_fsockopen($host,$path,$content);
1298
- */
1299
-
1300
-
1301
- if($response) {
1302
- list ($resultCode, $code, $text, $subscriptionId) = $this->parse_return($response);
1303
-
1304
- if($resultCode == "Ok" || $code == "Ok")
1305
- {
1306
- return true;
1307
- }
1308
- else
1309
- {
1310
- $this->status = "error";
1311
- $this->errorcode = $code;
1312
- $this->error = $text;
1313
- $this->shorterror = $text;
1314
- return false;
1315
- }
1316
- } else {
1317
- $this->status = "error";
1318
- $this->error = "Could not connect to Authorize.net";
1319
- $this->shorterror = "Could not connect to Authorize.net";
1320
- return false;
1321
- }
1322
  }
1323
  }
1324
- ?>
3
  {
4
  function MemberOrder($id = NULL)
5
  {
6
+ //setup the gateway
7
+ $this->setGateway(pmpro_getOption("gateway"));
8
+
9
+ //get data if an id was passed
10
  if($id)
11
  {
12
  if(is_numeric($id))
16
  }
17
  else
18
  return true; //blank constructor
19
+ }
20
 
21
  function getMemberOrderByID($id)
22
  {
29
  $dbobj = $wpdb->get_row("SELECT *, UNIX_TIMESTAMP(timestamp) + " . ($gmt_offset * 3600) . " as timestamp FROM $wpdb->pmpro_membership_orders WHERE id = '$id' LIMIT 1");
30
 
31
  if($dbobj)
32
+ {
33
  $this->id = $dbobj->id;
34
  $this->code = $dbobj->code;
35
  $this->session_id = $dbobj->session_id;
36
  $this->user_id = $dbobj->user_id;
37
  $this->membership_id = $dbobj->membership_id;
38
+ $this->paypal_token = $dbobj->paypal_token;
39
+ $this->billing = new stdClass();
40
  $this->billing->name = $dbobj->billing_name;
41
  $this->billing->street = $dbobj->billing_street;
42
  $this->billing->city = $dbobj->billing_city;
43
  $this->billing->state = $dbobj->billing_state;
44
  $this->billing->zip = $dbobj->billing_zip;
45
+ $this->billing->country = $dbobj->billing_country;
46
  $this->billing->phone = $dbobj->billing_phone;
47
 
48
  //split up some values
49
  $nameparts = pnp_split_full_name($this->billing->name);
50
+
51
+ if(!empty($nameparts['fname']))
52
+ $this->FirstName = $nameparts['fname'];
53
+ else
54
+ $this->FirstName = "";
55
+ if(!empty($nameparts['lname']))
56
+ $this->LastName = $nameparts['lname'];
57
+ else
58
+ $this->LastName = "";
59
+
60
  $this->Address1 = $this->billing->street;
61
 
62
  //get email from user_id
87
  $this->affiliate_id = $dbobj->affiliate_id;
88
  $this->affiliate_subid = $dbobj->affiliate_subid;
89
 
90
+ $this->notes = $dbobj->notes;
91
+
92
+ //reset the gateway
93
+ if(empty($this->nogateway))
94
+ $this->setGateway();
95
+
96
  return $this->id;
97
  }
98
  else
99
  return false; //didn't find it in the DB
100
  }
101
 
102
+ function setGateway($gateway = NULL)
103
+ {
104
+ //set the gateway property
105
+ if(isset($gateway))
106
+ {
107
+ $this->gateway = $gateway;
108
+ }
109
+
110
+ //which one to load?
111
+ $classname = "PMProGateway"; //default test gateway
112
+ if(!empty($this->gateway) && $this->gateway != "free")
113
+ $classname .= "_" . $this->gateway; //adding the gateway suffix
114
+
115
+ //try to load it
116
+ include_once(dirname(__FILE__) . "/gateways/class." . strtolower($classname) . ".php");
117
+ if(class_exists($classname))
118
+ $this->Gateway = new $classname($this->gateway);
119
+ else
120
+ {
121
+ $error = new WP_Error("PMPro1001", "Could not locate the gateway class file with class name = " . $classname . ".");
122
+ //die("Could not locate the gateway class file with class name = " . $classname . ".");
123
+ }
124
+
125
+ return $this->Gateway;
126
+ }
127
+
128
+ function getLastMemberOrder($user_id = NULL, $status = 'success', $membership_id = NULL)
129
  {
130
  global $current_user, $wpdb;
131
  if(!$user_id)
134
  if(!$user_id)
135
  return false;
136
 
137
+ //build query
138
+ $this->sqlQuery = "SELECT id FROM $wpdb->pmpro_membership_orders WHERE user_id = '" . $user_id . "' ";
139
+ if(!empty($status) && is_array($status))
140
+ $this->sqlQuery .= "AND status IN('" . implode("','", $status) . "') ";
141
+ elseif(!empty($status))
142
+ $this->sqlQuery .= "AND status = '" . esc_sql($status) . "' ";
143
+
144
+ if(!empty($membership_id))
145
+ $this->sqlQuery .= "AND membership_id = '" . $membership_id . "' ";
146
+ $this->sqlQuery .= "ORDER BY timestamp DESC LIMIT 1";
147
+
148
+ //get id
149
+ $id = $wpdb->get_var($this->sqlQuery);
150
 
151
  return $this->getMemberOrderByID($id);
152
  }
153
 
154
+ /*
155
+ Returns the order using the given order code.
156
+ */
157
  function getMemberOrderByCode($code)
158
  {
159
  global $wpdb;
164
  return false;
165
  }
166
 
167
+ /*
168
+ Returns the last order using the given payment_transaction_id.
169
+ */
170
+ function getMemberOrderByPaymentTransactionID($payment_transaction_id)
171
+ {
172
+ //did they pass a trans id?
173
+ if(empty($payment_transaction_id))
174
+ return false;
175
+
176
+ global $wpdb;
177
+ $id = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_orders WHERE payment_transaction_id = '" . esc_sql($payment_transaction_id) . "' LIMIT 1");
178
+ if($id)
179
+ return $this->getMemberOrderByID($id);
180
+ else
181
+ return false;
182
+ }
183
+
184
+ /*
185
+ Returns the last order using the given subscription_transaction_id.
186
+ */
187
+ function getLastMemberOrderBySubscriptionTransactionID($subscription_transaction_id)
188
+ {
189
+ //did they pass a sub id?
190
+ if(empty($subscription_transaction_id))
191
+ return false;
192
+
193
+ global $wpdb;
194
+ $id = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_orders WHERE subscription_transaction_id = '" . esc_sql($subscription_transaction_id) . "' ORDER BY id DESC LIMIT 1");
195
+
196
+ if($id)
197
+ return $this->getMemberOrderByID($id);
198
+ else
199
+ return false;
200
+ }
201
+
202
+ function getMemberOrderByPayPalToken($token)
203
+ {
204
+ global $wpdb;
205
+ $id = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_orders WHERE paypal_token = '" . $token . "' LIMIT 1");
206
+ if($id)
207
+ return $this->getMemberOrderByID($id);
208
+ else
209
+ return false;
210
+ }
211
+
212
+ function getDiscountCode($force = false)
213
+ {
214
+ if(!empty($this->discount_code) && !$force)
215
+ return $this->discount_code;
216
+
217
+ global $wpdb;
218
+ $this->discount_code = $wpdb->get_row("SELECT dc.* FROM $wpdb->pmpro_discount_codes dc LEFT JOIN $wpdb->pmpro_discount_codes_uses dcu ON dc.id = dcu.code_id WHERE dcu.order_id = '" . $this->id . "' LIMIT 1");
219
+
220
+ //filter @since v1.7.14
221
+ $this->discount_code = apply_filters("pmpro_order_discount_code", $this->discount_code, $this);
222
+
223
+ return $this->discount_code;
224
+ }
225
+
226
  function getUser()
227
  {
228
  global $wpdb;
229
 
230
+ if(!empty($this->user))
231
+ return $this->user;
232
 
233
  $gmt_offset = get_option('gmt_offset');
234
  $this->user = $wpdb->get_row("SELECT *, UNIX_TIMESTAMP(user_registered) + " . ($gmt_offset * 3600) . " as user_registered FROM $wpdb->users WHERE ID = '" . $this->user_id . "' LIMIT 1");
235
  return $this->user;
236
  }
237
 
238
+ function getMembershipLevel($force = false)
239
  {
240
  global $wpdb;
241
 
242
+ if(!empty($this->membership_level) && empty($force))
243
  return $this->membership_level;
244
+
245
+ //check if there is an entry in memberships_users first
246
+ if(!empty($this->user_id))
247
+ {
248
+ $this->membership_level = $wpdb->get_row("SELECT l.id as level_id, l.name, l.description, l.allow_signups, l.expiration_number, l.expiration_period, mu.*, UNIX_TIMESTAMP(mu.startdate) as startdate, UNIX_TIMESTAMP(mu.enddate) as enddate, l.name, l.description, l.allow_signups FROM $wpdb->pmpro_membership_levels l LEFT JOIN $wpdb->pmpro_memberships_users mu ON l.id = mu.membership_id WHERE mu.status = 'active' AND l.id = '" . $this->membership_id . "' AND mu.user_id = '" . $this->user_id . "' LIMIT 1");
249
+
250
+ //fix the membership level id
251
+ if(!empty($this->membership_level->level_id))
252
+ $this->membership_level->id = $this->membership_level->level_id;
253
+ }
254
+
255
+ //okay, do I have a discount code to check? (if there is no membership_level->membership_id value, that means there was no entry in memberships_users)
256
+ if(!empty($this->discount_code) && empty($this->membership_level->membership_id))
257
+ {
258
+ if(!empty($this->discount_code->code))
259
+ $discount_code = $this->discount_code->code;
260
+ else
261
+ $discount_code = $this->discount_code;
262
+
263
+ $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 = '" . $this->membership_id . "' LIMIT 1";
264
 
265
+ $this->membership_level = $wpdb->get_row($sqlQuery);
266
+ }
267
+
268
+ //just get the info from the membership table (sigh, I really need to standardize the column names for membership_id/level_id) but we're checking if we got the information already or not
269
+ if(empty($this->membership_level->membership_id) && empty($this->membership_level->level_id))
270
+ {
271
+ $this->membership_level = $wpdb->get_row("SELECT l.* FROM $wpdb->pmpro_membership_levels l WHERE l.id = '" . $this->membership_id . "' LIMIT 1");
272
+ }
273
+
274
  return $this->membership_level;
275
  }
276
 
279
  //get options
280
  $tax_state = pmpro_getOption("tax_state");
281
  $tax_rate = pmpro_getOption("tax_rate");
282
+
283
+ //default
284
+ $tax = 0;
285
+
286
  //calculate tax
287
  if($tax_state && $tax_rate)
288
  {
289
  //we have values, is this order in the tax state?
290
+ if(!empty($this->billing) && trim(strtoupper($this->billing->state)) == trim(strtoupper($tax_state)))
291
+ {
 
 
 
292
  //return value, pass through filter
293
+ $tax = round((float)$price * (float)$tax_rate, 2);
294
  }
295
  }
296
 
297
+ //set values array for filter
298
+ $values = array("price" => $price, "tax_state" => $tax_state, "tax_rate" => $tax_rate);
299
+ if(!empty($this->billing->state))
300
+ $values['billing_state'] = $this->billing->state;
301
+ if(!empty($this->billing->city))
302
+ $values['billing_city'] = $this->billing->city;
303
+ if(!empty($this->billing->zip))
304
+ $values['billing_zip'] = $this->billing->zip;
305
+ if(!empty($this->billing->country))
306
+ $values['billing_country'] = $this->billing->country;
307
+
308
+ //filter
309
+ $tax = apply_filters("pmpro_tax", $tax, $values, $this);
310
+ return $tax;
311
  }
312
 
313
  function getTax($force = false)
314
  {
315
+ if(!empty($this->tax) && !$force)
316
  return $this->tax;
317
 
318
  //reset
321
  return $this->tax;
322
  }
323
 
324
+ function updateTimestamp($year, $month, $day, $time = NULL)
325
  {
326
+ if(empty($this->id))
327
+ return false; //need a saved order
328
+
329
+ if(empty($time))
330
+ $time = "00:00:00";
331
+
332
+ $date = $year . "-" . $month . "-" . $day . " " . $time;
333
+
334
+ global $wpdb;
335
+ $this->sqlQuery = "UPDATE $wpdb->pmpro_membership_orders SET timestamp = '" . $date . "' WHERE id = '" . $this->id . "' LIMIT 1";
336
+
337
+ if($wpdb->query($this->sqlQuery) !== "false")
338
+ return $this->getMemberOrderByID($this->id);
339
+ else
340
+ return false;
341
+ }
342
+
343
+ function saveOrder()
344
+ {
345
  global $current_user, $wpdb;
346
 
347
  //get a random code to use for the public ID
348
+ if(empty($this->code))
349
  $this->code = $this->getRandomCode();
350
 
351
  //figure out how much we charged
352
+ if(!empty($this->InitialPayment))
353
+ $amount = $this->InitialPayment;
354
+ elseif(!empty($this->subtotal))
355
+ $amount = $this->subtotal;
356
+ else
357
+ $amount = 0;
358
+
359
  //Todo: Tax?!, Coupons, Certificates, affiliates
360
+ if(empty($this->subtotal))
361
+ $this->subtotal = $amount;
362
+ if(isset($this->tax))
363
+ $tax = $this->tax;
364
+ else
365
+ $tax = $this->getTax(true);
366
+ $this->certificate_id = "";
367
+ $this->certificateamount = "";
368
 
369
+ //calculate total
370
+ if(!empty($this->total))
371
+ $total = $this->total;
372
+ else
373
+ $total = (float)$amount + (float)$tax;
374
+
375
+ //these fix some warnings/notices
376
+ if(empty($this->billing))
377
+ {
378
+ $this->billing = new stdClass();
379
+ $this->billing->name = $this->billing->street = $this->billing->city = $this->billing->state = $this->billing->zip = $this->billing->country = $this->billing->phone = "";
380
+ }
381
+ if(empty($this->user_id))
382
+ $this->user_id = 0;
383
+ if(empty($this->paypal_token))
384
+ $this->paypal_token = "";
385
+ if(empty($this->couponamount))
386
+ $this->couponamount = "";
387
+ if(empty($this->payment_type))
388
+ $this->payment_type = "";
389
+ if(empty($this->payment_transaction_id))
390
+ $this->payment_transaction_id = "";
391
+ if(empty($this->subscription_transaction_id))
392
+ $this->subscription_transaction_id = "";
393
+ if(empty($this->affiliate_id))
394
+ $this->affiliate_id = "";
395
+ if(empty($this->affiliate_subid))
396
+ $this->affiliate_subid = "";
397
+ if(empty($this->session_id))
398
+ $this->session_id = "";
399
+ if(empty($this->accountnumber))
400
+ $this->accountnumber = "";
401
+ if(empty($this->cardtype))
402
+ $this->cardtype = "";
403
+ if(empty($this->ExpirationDate))
404
+ $this->ExpirationDate = "";
405
+ if (empty($this->status))
406
+ $this->status = "";
407
+
408
+ if(empty($this->gateway))
409
+ $this->gateway = pmpro_getOption("gateway");
410
+ if(empty($this->gateway_environment))
411
+ $this->gateway_environment = pmpro_getOption("gateway_environment");
412
+
413
+ if(empty($this->notes))
414
+ $this->notes = "";
415
 
416
  //build query
417
+ if(!empty($this->id))
418
+ {
419
+ //set up actions
420
+ $before_action = "pmpro_update_order";
421
+ $after_action = "pmpro_updated_order";
422
+ //update
423
+ $this->sqlQuery = "UPDATE $wpdb->pmpro_membership_orders
424
+ SET `code` = '" . $this->code . "',
425
+ `session_id` = '" . $this->session_id . "',
426
+ `user_id` = " . intval($this->user_id) . ",
427
+ `membership_id` = " . intval($this->membership_id) . ",
428
+ `paypal_token` = '" . $this->paypal_token . "',
429
+ `billing_name` = '" . esc_sql($this->billing->name) . "',
430
+ `billing_street` = '" . esc_sql($this->billing->street) . "',
431
+ `billing_city` = '" . esc_sql($this->billing->city) . "',
432
+ `billing_state` = '" . esc_sql($this->billing->state) . "',
433
+ `billing_zip` = '" . esc_sql($this->billing->zip) . "',
434
+ `billing_country` = '" . esc_sql($this->billing->country) . "',
435
+ `billing_phone` = '" . esc_sql($this->billing->phone) . "',
436
+ `subtotal` = '" . $this->subtotal . "',
437
+ `tax` = '" . $this->tax . "',
438
+ `couponamount` = '" . $this->couponamount . "',
439
+ `certificate_id` = " . intval($this->certificate_id) . ",
440
+ `certificateamount` = '" . $this->certificateamount . "',
441
+ `total` = '" . $this->total . "',
442
+ `payment_type` = '" . $this->payment_type . "',
443
+ `cardtype` = '" . $this->cardtype . "',
444
+ `accountnumber` = '" . $this->accountnumber . "',
445
+ `expirationmonth` = '" . $this->expirationmonth . "',
446
+ `expirationyear` = '" . $this->expirationyear . "',
447
+ `status` = '" . esc_sql($this->status) . "',
448
+ `gateway` = '" . $this->gateway . "',
449
+ `gateway_environment` = '" . $this->gateway_environment . "',
450
+ `payment_transaction_id` = '" . esc_sql($this->payment_transaction_id) . "',
451
+ `subscription_transaction_id` = '" . esc_sql($this->subscription_transaction_id) . "',
452
+ `affiliate_id` = '" . esc_sql($this->affiliate_id) . "',
453
+ `affiliate_subid` = '" . esc_sql($this->affiliate_subid) . "',
454
+ `notes` = '" . esc_sql($this->notes) . "'
455
+ WHERE id = '" . $this->id . "'
456
+ LIMIT 1";
457
+ }
458
+ else
459
+ {
460
+ //set up actions
461
+ $before_action = "pmpro_add_order";
462
+ $after_action = "pmpro_added_order";
463
+ //insert
464
+ $this->sqlQuery = "INSERT INTO $wpdb->pmpro_membership_orders
465
+ (`code`, `session_id`, `user_id`, `membership_id`, `paypal_token`, `billing_name`, `billing_street`, `billing_city`, `billing_state`, `billing_zip`, `billing_country`, `billing_phone`, `subtotal`, `tax`, `couponamount`, `certificate_id`, `certificateamount`, `total`, `payment_type`, `cardtype`, `accountnumber`, `expirationmonth`, `expirationyear`, `status`, `gateway`, `gateway_environment`, `payment_transaction_id`, `subscription_transaction_id`, `timestamp`, `affiliate_id`, `affiliate_subid`, `notes`)
466
  VALUES('" . $this->code . "',
467
  '" . session_id() . "',
468
+ " . intval($this->user_id) . ",
469
+ " . intval($this->membership_id) . ",
470
+ '" . $this->paypal_token . "',
471
+ '" . esc_sql(trim($this->billing->name)) . "',
472
+ '" . esc_sql(trim($this->billing->street)) . "',
473
+ '" . esc_sql($this->billing->city) . "',
474
+ '" . esc_sql($this->billing->state) . "',
475
+ '" . esc_sql($this->billing->zip) . "',
476
+ '" . esc_sql($this->billing->country) . "',
477
  '" . cleanPhone($this->billing->phone) . "',
478
  '" . $amount . "',
479
  '" . $tax . "',
480
+ '" . $this->couponamount. "',
481
+ " . intval($this->certificate_id) . ",
482
+ '" . $this->certificateamount . "',
483
+ '" . $total . "',
484
+ '" . $this->payment_type . "',
485
  '" . $this->cardtype . "',
486
  '" . hideCardNumber($this->accountnumber, false) . "',
487
  '" . substr($this->ExpirationDate, 0, 2) . "',
488
  '" . substr($this->ExpirationDate, 2, 4) . "',
489
+ '" . esc_sql($this->status) . "',
490
+ '" . $this->gateway . "',
491
+ '" . $this->gateway_environment . "',
492
+ '" . esc_sql($this->payment_transaction_id) . "',
493
+ '" . esc_sql($this->subscription_transaction_id) . "',
494
+ '" . current_time('mysql') . "',
495
+ '" . esc_sql($this->affiliate_id) . "',
496
+ '" . esc_sql($this->affiliate_subid) . "',
497
+ '" . esc_sql($this->notes) . "'
498
+ )";
499
+ }
500
+
501
+ do_action($before_action, $this);
502
  if($wpdb->query($this->sqlQuery) !== false)
503
+ {
504
+ if(empty($this->id))
505
+ $this->id = $wpdb->insert_id;
506
+ do_action($after_action, $this);
507
+ return $this->getMemberOrderByID($this->id);
508
+ }
509
  else
510
+ {
511
  return false;
512
+ }
513
  }
514
 
515
  function getRandomCode()
516
  {
517
  global $wpdb;
518
 
519
+ while(empty($code))
520
  {
521
+ $scramble = md5(AUTH_KEY . current_time('timestamp') . SECURE_AUTH_KEY);
522
  $code = substr($scramble, 0, 10);
523
+ $code = apply_filters("pmpro_random_code", $code, $this); //filter
524
  $check = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_orders WHERE code = '$code' LIMIT 1");
525
  if($check || is_numeric($code))
526
  $code = NULL;
533
  {
534
  global $wpdb;
535
 
536
+ if(empty($this->id))
537
  return false;
538
 
539
  $this->status = $newstatus;
540
+ $this->sqlQuery = "UPDATE $wpdb->pmpro_membership_orders SET status = '" . esc_sql($newstatus) . "' WHERE id = '" . $this->id . "' LIMIT 1";
541
  if($wpdb->query($this->sqlQuery) !== false)
542
  return true;
543
  else
546
 
547
  function process()
548
  {
549
+ return $this->Gateway->process($this);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
550
  }
551
 
552
  function cancel()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
553
  {
554
+ //only need to cancel on the gateway if there is a subscription id
555
+ if(empty($this->subscription_transaction_id))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
556
  {
557
+ //just mark as cancelled
558
+ $this->updateStatus("cancelled");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
559
  return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
560
  }
561
  else
562
+ {
563
+ //cancel the gateway subscription first
564
+ $result = $this->Gateway->cancel($this);
565
+ if($result == false)
 
 
 
566
  {
567
+ //there was an error, but cancel the order no matter what
568
+ $this->updateStatus("cancelled");
569
+
570
+ //we should probably notify the admin
571
+ $pmproemail = new PMProEmail();
572
+ $pmproemail->template = "subscription_cancel_error";
573
+ $pmproemail->data = array("body"=>"<p>" . sprintf(__("There was an error canceling the subscription for user with ID=%s. You will want to check your payment gateway to see if their subscription is still active.", "pmpro"), strval($this->user_id)) . "</p><p>Error: " . $this->error . "</p>");
574
+ $pmproemail->data["body"] .= "<p>Associated Order:<br />" . nl2br(var_export($this, true)) . "</p>";
575
+ $pmproemail->sendEmail(get_bloginfo("admin_email"));
576
+
577
+ return false;
578
+ }
579
+ else
580
+ {
581
+ //would have been cancelled by the gateway class
582
+ return $result;
583
  }
 
 
584
  }
 
585
  }
586
+
587
+ function updateBilling()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
588
  {
589
+ return $this->Gateway->update($this);
590
+ }
591
+
592
+ function getGatewaySubscriptionStatus()
 
 
 
 
 
 
 
593
  {
594
+ return $this->Gateway->getSubscriptionStatus($this);
 
 
 
 
 
 
 
 
 
595
  }
596
 
597
+ function getGatewayTransactionStatus()
 
598
  {
599
+ return $this->Gateway->getTransactionStatus($this);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
  }
601
 
602
+ function deleteMe()
 
603
  {
604
+ if(empty($this->id))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
605
  return false;
 
 
 
 
 
 
 
 
 
606
 
607
+ global $wpdb;
608
+ $this->sqlQuery = "DELETE FROM $wpdb->pmpro_membership_orders WHERE id = '" . $this->id . "' LIMIT 1";
609
+ if($wpdb->query($this->sqlQuery) !== false)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
610
  {
611
+ do_action("pmpro_delete_order", $this->id, $this);
612
+ return true;
613
  }
614
  else
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
615
  return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
616
  }
617
  }
 
classes/class.pmproemail.php CHANGED
@@ -3,6 +3,7 @@
3
  {
4
  function PMProEmail()
5
  {
 
6
  }
7
 
8
  function sendEmail($email = NULL, $from = NULL, $fromname = NULL, $subject = NULL, $template = NULL, $data = NULL)
@@ -33,18 +34,37 @@
33
  $this->fromname = pmpro_getOption("from_name");
34
 
35
  if(!$this->subject)
36
- $this->subject = "An Email From " . get_option("blogname");
37
-
 
 
 
38
  if(!$this->template)
39
  $this->template = "default";
 
 
40
 
41
- //load the template
42
- if(file_exists(TEMPLATEPATH . "/membership-email-" . $this->template . ".html"))
43
- $this->body = file_get_contents(TEMPLATEPATH . "/membership-email-" . $this->template . ".html");
44
- else
45
- $this->body = file_get_contents(ABSPATH . "/wp-content/plugins/paid-memberships-pro/email/" . $this->template . ".html");
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
  //header and footer
 
48
  if(file_exists(TEMPLATEPATH . "/email_header.html"))
49
  {
50
  $this->body = file_get_contents(TEMPLATEPATH . "/email_header.html") . "\n" . $this->body;
@@ -52,11 +72,17 @@
52
  if(file_exists(TEMPLATEPATH . "/email_footer.html"))
53
  {
54
  $this->body = $this->body . "\n" . file_get_contents(TEMPLATEPATH . "/email_footer.html");
55
- }
 
56
 
57
- //swap data
58
  if(is_string($this->data))
59
- $data = array("body"=>$data);
 
 
 
 
 
60
  if(is_array($this->data))
61
  {
62
  foreach($this->data as $key => $value)
@@ -65,24 +91,25 @@
65
  }
66
  }
67
 
68
- //prep email
69
- $this->mailer = new PHPMailer();
70
- $this->mailer->From = $this->from;
71
- $this->mailer->FromName = $this->fromname;
72
- $this->mailer->AddAddress($this->email);
73
- $this->mailer->Subject = $this->subject;
74
- $this->mailer->Body = $this->body;
75
- $this->mailer->AltBody = strip_tags(pmpro_br2nl($this->body, array("br", "p")));
76
-
77
- //send email
78
- if($this->mailer->send())
 
79
  {
80
  return true;
81
  }
82
  else
83
  {
84
  return false;
85
- }
86
  }
87
 
88
  function sendCancelEmail($user = NULL)
@@ -95,16 +122,52 @@
95
  return false;
96
 
97
  $this->email = $user->user_email;
98
- $this->subject = "Your membership at " . get_option("blogname") . " has been CANCELED";
99
  $this->template = "cancel";
100
- $this->data = array("name" => $user->display_name, "sitename" => get_option("blogname"), "siteemail" => pmpro_getOption("from_email"));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  return $this->sendEmail();
103
  }
104
 
105
  function sendCheckoutEmail($user = NULL, $invoice = NULL)
106
  {
107
- global $current_user;
108
  if(!$user)
109
  $user = $current_user;
110
 
@@ -112,48 +175,180 @@
112
  return false;
113
 
114
  $this->email = $user->user_email;
115
- $this->subject = "Your membership confirmation for " . get_option("blogname");
116
 
117
  $this->data = array(
118
  "subject" => $this->subject,
119
  "name" => $user->display_name,
 
120
  "sitename" => get_option("blogname"),
121
  "siteemail" => pmpro_getOption("from_email"),
 
122
  "membership_level_name" => $user->membership_level->name,
123
  "membership_cost" => pmpro_getLevelCost($user->membership_level),
124
- "login_link" => pmpro_url("account"),
125
  "display_name" => $user->display_name,
126
  "user_email" => $user->user_email,0
127
  );
128
-
129
- if($invoice)
130
  {
131
- if(pmpro_isLevelTrial($user->membership_level))
 
 
 
 
 
 
 
132
  $this->template = "checkout_trial";
133
  else
134
  $this->template = "checkout_paid";
135
  $this->data["invoice_id"] = $invoice->code;
136
- $this->data["invoice_total"] = number_format($invoice->total, 2);
137
- $this->data["invoice_date"] = date("F j, Y", $invoice->timestamp);
138
  $this->data["billing_name"] = $invoice->billing->name;
139
  $this->data["billing_street"] = $invoice->billing->street;
140
  $this->data["billing_city"] = $invoice->billing->city;
141
  $this->data["billing_state"] = $invoice->billing->state;
142
  $this->data["billing_zip"] = $invoice->billing->zip;
 
143
  $this->data["billing_phone"] = $invoice->billing->phone;
144
  $this->data["cardtype"] = $invoice->cardtype;
145
  $this->data["accountnumber"] = hideCardNumber($invoice->accountnumber);
146
  $this->data["expirationmonth"] = $invoice->expirationmonth;
147
  $this->data["expirationyear"] = $invoice->expirationyear;
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  }
149
  elseif(pmpro_isLevelFree($user->membership_level))
150
  {
151
- $this->template = "checkout_free";
 
 
 
 
 
152
  }
153
  else
154
  {
155
  $this->template = "checkout_freetrial";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
  return $this->sendEmail();
159
  }
@@ -168,13 +363,69 @@
168
  return false;
169
 
170
  $this->email = $user->user_email;
171
- $this->subject = "Your billing information has been udpated at " . get_option("blogname");
172
  $this->template = "billing";
173
 
174
  $this->data = array(
175
  "subject" => $this->subject,
176
  "name" => $user->display_name,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  "sitename" => get_option("blogname"),
 
 
178
  "membership_level_name" => $user->membership_level->name,
179
  "display_name" => $user->display_name,
180
  "user_email" => $user->user_email,
@@ -183,13 +434,22 @@
183
  "billing_city" => $invoice->billing->city,
184
  "billing_state" => $invoice->billing->state,
185
  "billing_zip" => $invoice->billing->zip,
 
186
  "billing_phone" => $invoice->billing->phone,
187
  "cardtype" => $invoice->cardtype,
188
  "accountnumber" => hideCardNumber($invoice->accountnumber),
189
  "expirationmonth" => $invoice->expirationmonth,
190
  "expirationyear" => $invoice->expirationyear,
191
- "login_link" => pmpro_url("account")
192
  );
 
 
 
 
 
 
 
 
193
 
194
  return $this->sendEmail();
195
  }
@@ -204,13 +464,16 @@
204
  return false;
205
 
206
  $this->email = $user->user_email;
207
- $this->subject = "Membership Payment Failed at " . get_option("blogname");
208
  $this->template = "billing_failure";
209
 
210
  $this->data = array(
211
  "subject" => $this->subject,
212
  "name" => $user->display_name,
 
213
  "sitename" => get_option("blogname"),
 
 
214
  "membership_level_name" => $user->membership_level->name,
215
  "display_name" => $user->display_name,
216
  "user_email" => $user->user_email,
@@ -219,16 +482,25 @@
219
  "billing_city" => $invoice->billing->city,
220
  "billing_state" => $invoice->billing->state,
221
  "billing_zip" => $invoice->billing->zip,
 
222
  "billing_phone" => $invoice->billing->phone,
223
  "cardtype" => $invoice->cardtype,
224
  "accountnumber" => hideCardNumber($invoice->accountnumber),
225
  "expirationmonth" => $invoice->expirationmonth,
226
  "expirationyear" => $invoice->expirationyear,
227
- "login_link" => pmpro_url("billing")
228
  );
 
 
 
 
 
 
 
 
229
 
230
  return $this->sendEmail();
231
- }
232
 
233
  function sendBillingFailureAdminEmail($email, $invoice = NULL)
234
  {
@@ -238,13 +510,16 @@
238
  $user = get_userdata($invoice->user_id);
239
 
240
  $this->email = $email;
241
- $this->subject = "Membership Payment Failed For " . $user->display_name . " at " . get_option("blogname");
242
  $this->template = "billing_failure_admin";
243
 
244
  $this->data = array(
245
  "subject" => $this->subject,
246
  "name" => "Admin",
 
247
  "sitename" => get_option("blogname"),
 
 
248
  "membership_level_name" => $user->membership_level->name,
249
  "display_name" => $user->display_name,
250
  "user_email" => $user->user_email,
@@ -253,20 +528,76 @@
253
  "billing_city" => $invoice->billing->city,
254
  "billing_state" => $invoice->billing->state,
255
  "billing_zip" => $invoice->billing->zip,
 
256
  "billing_phone" => $invoice->billing->phone,
257
  "cardtype" => $invoice->cardtype,
258
  "accountnumber" => hideCardNumber($invoice->accountnumber),
259
  "expirationmonth" => $invoice->expirationmonth,
260
  "expirationyear" => $invoice->expirationyear,
261
- "login_link" => pmpro_url("billing")
262
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
 
264
  return $this->sendEmail();
265
  }
266
 
267
  function sendInvoiceEmail($user = NULL, $invoice = NULL)
268
  {
269
- global $current_user;
270
  if(!$user)
271
  $user = $current_user;
272
 
@@ -274,37 +605,119 @@
274
  return false;
275
 
276
  $this->email = $user->user_email;
277
- $this->subject = "INVOICE for " . get_option("blogname") . " membership";
278
  $this->template = "invoice";
279
 
280
  $this->data = array(
281
  "subject" => $this->subject,
282
  "name" => $user->display_name,
 
283
  "sitename" => get_option("blogname"),
 
 
284
  "membership_level_name" => $user->membership_level->name,
285
  "display_name" => $user->display_name,
286
  "user_email" => $user->user_email,
287
- "invoice_id" => $invoice->payment_transaction_id,
288
- "invoice_total" => number_format($invoice->total, 2),
289
- "invoice_date" => date("F j, Y", $invoice->timestamp),
290
  "billing_name" => $invoice->billing->name,
291
  "billing_street" => $invoice->billing->street,
292
  "billing_city" => $invoice->billing->city,
293
  "billing_state" => $invoice->billing->state,
294
  "billing_zip" => $invoice->billing->zip,
 
295
  "billing_phone" => $invoice->billing->phone,
296
  "cardtype" => $invoice->cardtype,
297
  "accountnumber" => hideCardNumber($invoice->accountnumber),
298
  "expirationmonth" => $invoice->expirationmonth,
299
  "expirationyear" => $invoice->expirationyear,
300
- "login_link" => pmpro_url("account"),
301
- "invoice_link" => pmpro_url("invoice", "?invoice=" . $invoice->code)
302
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
303
 
 
 
 
 
 
 
304
  return $this->sendEmail();
305
  }
306
 
307
- function sendAdminChangeEmail($user = NULL)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  {
309
  global $current_user, $wpdb;
310
  if(!$user)
@@ -314,22 +727,89 @@
314
  return false;
315
 
316
  //make sure we have the current membership level data
317
- $user->membership_level = $wpdb->get_row("SELECT l.id AS ID, l.name AS name
318
  FROM {$wpdb->pmpro_membership_levels} AS l
319
  JOIN {$wpdb->pmpro_memberships_users} AS mu ON (l.id = mu.membership_id)
320
  WHERE mu.user_id = " . $user->ID . "
321
- LIMIT 1");
 
322
 
323
  $this->email = $user->user_email;
324
- $this->subject = "Your membership at " . get_option("blogname") . " has been changed";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
  $this->template = "admin_change";
326
- $this->data = array("subject" => $this->subject, "name" => $user->display_name, "sitename" => get_option("blogname"), "membership_level_name" => $user->membership_level->name, "siteemail" => get_bloginfo("admin_email"), "login_link" => wp_login_url());
327
  if($user->membership_level->ID)
328
- $this->data["membership_change"] = "new level is " . $user->membership_level->name . ". This membership is free";
329
  else
330
- $this->data["membership_change"] = "membership has been canceled";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
 
332
  return $this->sendEmail();
333
  }
334
  }
335
- ?>
3
  {
4
  function PMProEmail()
5
  {
6
+ $this->email = $this->from = $this->fromname = $this->subject = $this->template = $this->data = $this->body = NULL;
7
  }
8
 
9
  function sendEmail($email = NULL, $from = NULL, $fromname = NULL, $subject = NULL, $template = NULL, $data = NULL)
34
  $this->fromname = pmpro_getOption("from_name");
35
 
36
  if(!$this->subject)
37
+ $this->subject = sprintf(__("An Email From %s", "pmpro"), get_option("blogname"));
38
+
39
+ //decode the subject line in case there are apostrophes/etc in it
40
+ $this->subject = html_entity_decode($this->subject, ENT_QUOTES, 'UTF-8');
41
+
42
  if(!$this->template)
43
  $this->template = "default";
44
+
45
+ $this->headers = array("Content-Type: text/html");
46
 
47
+ $this->attachments = NULL;
48
+
49
+ //load the template
50
+ $locale = apply_filters("plugin_locale", get_locale(), "pmpro");
51
+ if(file_exists(get_stylesheet_directory() . "/paid-memberships-pro/email/" . $this->template . ".html"))
52
+ $this->body = file_get_contents(get_stylesheet_directory() . "/paid-memberships-pro/email/" . $this->template . ".html"); //email folder in pmpro folder in theme
53
+ elseif(file_exists(get_stylesheet_directory() . "/membership-email-" . $this->template . ".html"))
54
+ $this->body = file_get_contents(get_stylesheet_directory() . "/membership-email-" . $this->template . ".html"); //membership- file in pmpro folder in theme
55
+ elseif(file_exists(TEMPLATEPATH . "/membership-email-" . $this->template . ".html"))
56
+ $this->body = file_get_contents(TEMPLATEPATH . "/membership-email-" . $this->template . ".html"); //membership- file in theme root
57
+ elseif(file_exists(WP_LANG_DIR . '/pmpro/email/' . $this->template . ".html"))
58
+ $this->body = file_get_contents(WP_LANG_DIR . '/pmpro/email/' . $this->template . ".html"); //email folder in WP language folder
59
+ elseif(file_exists(PMPRO_DIR . "/languages/" . $locale . "/" . $this->template . ".html"))
60
+ $this->body = file_get_contents(PMPRO_DIR . "/languages/" . $locale . "/" . $this->template . ".html"); //email folder in PMPro language folder
61
+ elseif(file_exists(PMPRO_DIR . "/email/" . $this->template . ".html"))
62
+ $this->body = file_get_contents(PMPRO_DIR . "/email/" . $this->template . ".html"); //default template in plugin
63
+ elseif(!empty($this->data) && !empty($this->data['body']))
64
+ $this->body = $this->data['body'];
65
 
66
  //header and footer
67
+ /* This is handled for all emails via the pmpro_send_html function in paid-memberships-pro now
68
  if(file_exists(TEMPLATEPATH . "/email_header.html"))
69
  {
70
  $this->body = file_get_contents(TEMPLATEPATH . "/email_header.html") . "\n" . $this->body;
72
  if(file_exists(TEMPLATEPATH . "/email_footer.html"))
73
  {
74
  $this->body = $this->body . "\n" . file_get_contents(TEMPLATEPATH . "/email_footer.html");
75
+ }
76
+ */
77
 
78
+ //if data is a string, assume we mean to replace !!body!! with it
79
  if(is_string($this->data))
80
+ $this->data = array("body"=>$data);
81
+
82
+ //filter for data
83
+ $this->data = apply_filters("pmpro_email_data", $this->data, $this); //filter
84
+
85
+ //swap data into body
86
  if(is_array($this->data))
87
  {
88
  foreach($this->data as $key => $value)
91
  }
92
  }
93
 
94
+ //filters
95
+ $temail = apply_filters("pmpro_email_filter", $this); //allows filtering entire email at once
96
+ $this->email = apply_filters("pmpro_email_recipient", $temail->email, $this);
97
+ $this->from = apply_filters("pmpro_email_sender", $temail->from, $this);
98
+ $this->fromname = apply_filters("pmpro_email_sender_name", $temail->fromname, $this);
99
+ $this->subject = apply_filters("pmpro_email_subject", $temail->subject, $this);
100
+ $this->template = apply_filters("pmpro_email_template", $temail->template, $this);
101
+ $this->body = apply_filters("pmpro_email_body", $temail->body, $this);
102
+ $this->headers = apply_filters("pmpro_email_headers", $temail->headers, $this);
103
+ $this->attachments = apply_filters("pmpro_email_attachments", $temail->attachments, $this);
104
+
105
+ if(wp_mail($this->email,$this->subject,$this->body,$this->headers,$this->attachments))
106
  {
107
  return true;
108
  }
109
  else
110
  {
111
  return false;
112
+ }
113
  }
114
 
115
  function sendCancelEmail($user = NULL)
122
  return false;
123
 
124
  $this->email = $user->user_email;
125
+ $this->subject = sprintf(__("Your membership at %s has been CANCELLED", "pmpro"), get_option("blogname"));
126
  $this->template = "cancel";
127
+ $this->data = array("name" => $user->display_name, "user_login" => $user->user_login, "sitename" => get_option("blogname"), "siteemail" => pmpro_getOption("from_email"));
128
+
129
+ return $this->sendEmail();
130
+ }
131
+
132
+ function sendCancelAdminEmail($user = NULL, $old_level_id)
133
+ {
134
+ global $wpdb, $current_user;
135
+ if(!$user)
136
+ $user = $current_user;
137
+
138
+ if(!$user)
139
+ return false;
140
+
141
+ //check settings
142
+ $send = pmpro_getOption("email_admin_cancels");
143
+ if(empty($send))
144
+ return true; //didn't send, but we also don't want to indicate failure because the settings say to not send
145
 
146
+ $this->email = get_bloginfo("admin_email");
147
+ $this->subject = sprintf(__("Membership for %s at %s has been CANCELLED", "pmpro"), $user->user_login, get_option("blogname"));
148
+ $this->template = "cancel_admin";
149
+ $this->data = array("user_login" => $user->user_login, "user_email" => $user->user_email, "display_name" => $user->display_name, "sitename" => get_option("blogname"), "siteemail" => pmpro_getOption("from_email"), "login_link" => wp_login_url());
150
+ $this->data['membership_id'] = $old_level_id;
151
+ $this->data['membership_level_name'] = $wpdb->get_var("SELECT name FROM $wpdb->pmpro_membership_levels WHERE id = '" . $old_level_id . "' LIMIT 1");
152
+
153
+ //start and end date
154
+ $startdate = $wpdb->get_var("SELECT UNIX_TIMESTAMP(startdate) as startdate FROM $wpdb->pmpro_memberships_users WHERE user_id = '" . $user->ID . "' AND membership_id = '" . $old_level_id . "' AND status = 'inactive' ORDER BY id DESC");
155
+ if(!empty($startdate))
156
+ $this->data['startdate'] = date(get_option('date_format'), $startdate);
157
+ else
158
+ $this->data['startdate'] = "";
159
+ $enddate = $wpdb->get_var("SELECT UNIX_TIMESTAMP(enddate) as enddate FROM $wpdb->pmpro_memberships_users WHERE user_id = '" . $user->ID . "' AND membership_id = '" . $old_level_id . "' AND status = 'inactive' ORDER BY id DESC");
160
+ if(!empty($enddate))
161
+ $this->data['enddate'] = date(get_option('date_format'), $enddate);
162
+ else
163
+ $this->data['enddate'] = "";
164
+
165
  return $this->sendEmail();
166
  }
167
 
168
  function sendCheckoutEmail($user = NULL, $invoice = NULL)
169
  {
170
+ global $wpdb, $current_user;
171
  if(!$user)
172
  $user = $current_user;
173
 
175
  return false;
176
 
177
  $this->email = $user->user_email;
178
+ $this->subject = sprintf(__("Your membership confirmation for %s", "pmpro"), get_option("blogname"));
179
 
180
  $this->data = array(
181
  "subject" => $this->subject,
182
  "name" => $user->display_name,
183
+ "user_login" => $user->user_login,
184
  "sitename" => get_option("blogname"),
185
  "siteemail" => pmpro_getOption("from_email"),
186
+ "membership_id" => $user->membership_level->id,
187
  "membership_level_name" => $user->membership_level->name,
188
  "membership_cost" => pmpro_getLevelCost($user->membership_level),
189
+ "login_link" => wp_login_url(pmpro_url("account")),
190
  "display_name" => $user->display_name,
191
  "user_email" => $user->user_email,0
192
  );
193
+
194
+ if(!empty($invoice) && !pmpro_isLevelFree($user->membership_level))
195
  {
196
+ if($invoice->gateway == "paypalexpress")
197
+ $this->template = "checkout_express";
198
+ elseif($invoice->gateway == "check")
199
+ {
200
+ $this->template = "checkout_check";
201
+ $this->data["instructions"] = wpautop(pmpro_getOption("instructions"));
202
+ }
203
+ elseif(pmpro_isLevelTrial($user->membership_level))
204
  $this->template = "checkout_trial";
205
  else
206
  $this->template = "checkout_paid";
207
  $this->data["invoice_id"] = $invoice->code;
208
+ $this->data["invoice_total"] = pmpro_formatPrice($invoice->total);
209
+ $this->data["invoice_date"] = date(get_option('date_format'), $invoice->timestamp);
210
  $this->data["billing_name"] = $invoice->billing->name;
211
  $this->data["billing_street"] = $invoice->billing->street;
212
  $this->data["billing_city"] = $invoice->billing->city;
213
  $this->data["billing_state"] = $invoice->billing->state;
214
  $this->data["billing_zip"] = $invoice->billing->zip;
215
+ $this->data["billing_country"] = $invoice->billing->country;
216
  $this->data["billing_phone"] = $invoice->billing->phone;
217
  $this->data["cardtype"] = $invoice->cardtype;
218
  $this->data["accountnumber"] = hideCardNumber($invoice->accountnumber);
219
  $this->data["expirationmonth"] = $invoice->expirationmonth;
220
  $this->data["expirationyear"] = $invoice->expirationyear;
221
+ $this->data["billing_address"] = pmpro_formatAddress($invoice->billing->name,
222
+ $invoice->billing->street,
223
+ "", //address 2
224
+ $invoice->billing->city,
225
+ $invoice->billing->state,
226
+ $invoice->billing->zip,
227
+ $invoice->billing->country,
228
+ $invoice->billing->phone);
229
+
230
+ if($invoice->getDiscountCode())
231
+ $this->data["discount_code"] = "<p>" . __("Discount Code", "pmpro") . ": " . $invoice->discount_code->code . "</p>\n";
232
+ else
233
+ $this->data["discount_code"] = "";
234
  }
235
  elseif(pmpro_isLevelFree($user->membership_level))
236
  {
237
+ $this->template = "checkout_free";
238
+ global $discount_code;
239
+ if(!empty($discount_code))
240
+ $this->data["discount_code"] = "<p>" . __("Discount Code", "pmpro") . ": " . $discount_code . "</p>\n";
241
+ else
242
+ $this->data["discount_code"] = "";
243
  }
244
  else
245
  {
246
  $this->template = "checkout_freetrial";
247
+ global $discount_code;
248
+ if(!empty($discount_code))
249
+ $this->data["discount_code"] = "<p>" . __("Discount Code", "pmpro") . ": " . $discount_code . "</p>\n";
250
+ else
251
+ $this->data["discount_code"] = "";
252
+ }
253
+
254
+ $enddate = $wpdb->get_var("SELECT UNIX_TIMESTAMP(enddate) FROM $wpdb->pmpro_memberships_users WHERE user_id = '" . $user->ID . "' AND status = 'active' LIMIT 1");
255
+ if($enddate)
256
+ $this->data["membership_expiration"] = "<p>" . sprintf(__("This membership will expire on %s.", "pmpro"), date(get_option('date_format'), $enddate)) . "</p>\n";
257
+ else
258
+ $this->data["membership_expiration"] = "";
259
+
260
+ return $this->sendEmail();
261
+ }
262
+
263
+ function sendCheckoutAdminEmail($user = NULL, $invoice = NULL)
264
+ {
265
+ global $wpdb, $current_user;
266
+ if(!$user)
267
+ $user = $current_user;
268
+
269
+ if(!$user)
270
+ return false;
271
+
272
+ //check settings
273
+ $send = pmpro_getOption("email_admin_checkout");
274
+ if(empty($send))
275
+ return true; //didn't send, but we also don't want to indicate failure because the settings say to not send
276
+
277
+ $this->email = get_bloginfo("admin_email");
278
+ $this->subject = sprintf(__("Member Checkout for %s at %s", "pmpro"), $user->membership_level->name, get_option("blogname"));
279
+
280
+ $this->data = array(
281
+ "subject" => $this->subject,
282
+ "name" => $user->display_name,
283
+ "user_login" => $user->user_login,
284
+ "sitename" => get_option("blogname"),
285
+ "siteemail" => pmpro_getOption("from_email"),
286
+ "membership_id" => $user->membership_level->id,
287
+ "membership_level_name" => $user->membership_level->name,
288
+ "membership_cost" => pmpro_getLevelCost($user->membership_level),
289
+ "login_link" => wp_login_url(pmpro_url("account")),
290
+ "display_name" => $user->display_name,
291
+ "user_email" => $user->user_email,0
292
+ );
293
+
294
+ if(!empty($invoice) && !pmpro_isLevelFree($user->membership_level))
295
+ {
296
+ if($invoice->gateway == "paypalexpress")
297
+ $this->template = "checkout_express_admin";
298
+ elseif($invoice->gateway == "check")
299
+ $this->template = "checkout_check_admin";
300
+ elseif(pmpro_isLevelTrial($user->membership_level))
301
+ $this->template = "checkout_trial_admin";
302
+ else
303
+ $this->template = "checkout_paid_admin";
304
+ $this->data["invoice_id"] = $invoice->code;
305
+ $this->data["invoice_total"] = pmpro_formatPrice($invoice->total);
306
+ $this->data["invoice_date"] = date(get_option('date_format'), $invoice->timestamp);
307
+ $this->data["billing_name"] = $invoice->billing->name;
308
+ $this->data["billing_street"] = $invoice->billing->street;
309
+ $this->data["billing_city"] = $invoice->billing->city;
310
+ $this->data["billing_state"] = $invoice->billing->state;
311
+ $this->data["billing_zip"] = $invoice->billing->zip;
312
+ $this->data["billing_country"] = $invoice->billing->country;
313
+ $this->data["billing_phone"] = $invoice->billing->phone;
314
+ $this->data["cardtype"] = $invoice->cardtype;
315
+ $this->data["accountnumber"] = hideCardNumber($invoice->accountnumber);
316
+ $this->data["expirationmonth"] = $invoice->expirationmonth;
317
+ $this->data["expirationyear"] = $invoice->expirationyear;
318
+ $this->data["billing_address"] = pmpro_formatAddress($invoice->billing->name,
319
+ $invoice->billing->street,
320
+ "", //address 2
321
+ $invoice->billing->city,
322
+ $invoice->billing->state,
323
+ $invoice->billing->zip,
324
+ $invoice->billing->country,
325
+ $invoice->billing->phone);
326
+
327
+ if($invoice->getDiscountCode())
328
+ $this->data["discount_code"] = "<p>" . __("Discount Code", "pmpro") . ": " . $invoice->discount_code->code . "</p>\n";
329
+ else
330
+ $this->data["discount_code"] = "";
331
  }
332
+ elseif(pmpro_isLevelFree($user->membership_level))
333
+ {
334
+ $this->template = "checkout_free_admin";
335
+ global $discount_code;
336
+ if(!empty($discount_code))
337
+ $this->data["discount_code"] = "<p>" . __("Discount Code", "pmpro") . ": " . $discount_code . "</p>\n";
338
+ else
339
+ $this->data["discount_code"] = "";
340
+ }
341
+ else
342
+ {
343
+ $this->template = "checkout_freetrial_admin";
344
+ $this->data["discount_code"] = "";
345
+ }
346
+
347
+ $enddate = $wpdb->get_var("SELECT UNIX_TIMESTAMP(enddate) FROM $wpdb->pmpro_memberships_users WHERE user_id = '" . $user->ID . "' AND status = 'active' LIMIT 1");
348
+ if($enddate)
349
+ $this->data["membership_expiration"] = "<p>" . sprintf(__("This membership will expire on %s.", "pmpro"), date(get_option('date_format'), $enddate)) . "</p>\n";
350
+ else
351
+ $this->data["membership_expiration"] = "";
352
 
353
  return $this->sendEmail();
354
  }
363
  return false;
364
 
365
  $this->email = $user->user_email;
366
+ $this->subject = sprintf(__("Your billing information has been udpated at %s", "pmpro"), get_option("blogname"));
367
  $this->template = "billing";
368
 
369
  $this->data = array(
370
  "subject" => $this->subject,
371
  "name" => $user->display_name,
372
+ "user_login" => $user->user_login,
373
+ "sitename" => get_option("blogname"),
374
+ "siteemail" => pmpro_getOption("from_email"),
375
+ "membership_id" => $user->membership_level->id,
376
+ "membership_level_name" => $user->membership_level->name,
377
+ "display_name" => $user->display_name,
378
+ "user_email" => $user->user_email,
379
+ "billing_name" => $invoice->billing->name,
380
+ "billing_street" => $invoice->billing->street,
381
+ "billing_city" => $invoice->billing->city,
382
+ "billing_state" => $invoice->billing->state,
383
+ "billing_zip" => $invoice->billing->zip,
384
+ "billing_country" => $invoice->billing->country,
385
+ "billing_phone" => $invoice->billing->phone,
386
+ "cardtype" => $invoice->cardtype,
387
+ "accountnumber" => hideCardNumber($invoice->accountnumber),
388
+ "expirationmonth" => $invoice->expirationmonth,
389
+ "expirationyear" => $invoice->expirationyear,
390
+ "login_link" => wp_login_url(pmpro_url("account"))
391
+ );
392
+ $this->data["billing_address"] = pmpro_formatAddress($invoice->billing->name,
393
+ $invoice->billing->street,
394
+ "", //address 2
395
+ $invoice->billing->city,
396
+ $invoice->billing->state,
397
+ $invoice->billing->zip,
398
+ $invoice->billing->country,
399
+ $invoice->billing->phone);
400
+
401
+ return $this->sendEmail();
402
+ }
403
+
404
+ function sendBillingAdminEmail($user = NULL, $invoice = NULL)
405
+ {
406
+ global $current_user;
407
+ if(!$user)
408
+ $user = $current_user;
409
+
410
+ if(!$user || !$invoice)
411
+ return false;
412
+
413
+ //check settings
414
+ $send = pmpro_getOption("email_admin_billing");
415
+ if(empty($send))
416
+ return true; //didn't send, but we also don't want to indicate failure because the settings say to not send
417
+
418
+ $this->email = get_bloginfo("admin_email");
419
+ $this->subject = sprintf(__("Billing information has been udpated for %s at %s", "pmpro"), $user->user_login, get_option("blogname"));
420
+ $this->template = "billing_admin";
421
+
422
+ $this->data = array(
423
+ "subject" => $this->subject,
424
+ "name" => $user->display_name,
425
+ "user_login" => $user->user_login,
426
  "sitename" => get_option("blogname"),
427
+ "siteemail" => pmpro_getOption("from_email"),
428
+ "membership_id" => $user->membership_level->id,
429
  "membership_level_name" => $user->membership_level->name,
430
  "display_name" => $user->display_name,
431
  "user_email" => $user->user_email,
434
  "billing_city" => $invoice->billing->city,
435
  "billing_state" => $invoice->billing->state,
436
  "billing_zip" => $invoice->billing->zip,
437
+ "billing_country" => $invoice->billing->country,
438
  "billing_phone" => $invoice->billing->phone,
439
  "cardtype" => $invoice->cardtype,
440
  "accountnumber" => hideCardNumber($invoice->accountnumber),
441
  "expirationmonth" => $invoice->expirationmonth,
442
  "expirationyear" => $invoice->expirationyear,
443
+ "login_link" => wp_login_url()
444
  );
445
+ $this->data["billing_address"] = pmpro_formatAddress($invoice->billing->name,
446
+ $invoice->billing->street,
447
+ "", //address 2
448
+ $invoice->billing->city,
449
+ $invoice->billing->state,
450
+ $invoice->billing->zip,
451
+ $invoice->billing->country,
452
+ $invoice->billing->phone);
453
 
454
  return $this->sendEmail();
455
  }
464
  return false;
465
 
466
  $this->email = $user->user_email;
467
+ $this->subject = sprintf(__("Membership Payment Failed at %s", "pmpro"), get_option("blogname"));
468
  $this->template = "billing_failure";
469
 
470
  $this->data = array(
471
  "subject" => $this->subject,
472
  "name" => $user->display_name,
473
+ "user_login" => $user->user_login,
474
  "sitename" => get_option("blogname"),
475
+ "siteemail" => pmpro_getOption("from_email"),
476
+ "membership_id" => $user->membership_level->id,
477
  "membership_level_name" => $user->membership_level->name,
478
  "display_name" => $user->display_name,
479
  "user_email" => $user->user_email,
482
  "billing_city" => $invoice->billing->city,
483
  "billing_state" => $invoice->billing->state,
484
  "billing_zip" => $invoice->billing->zip,
485
+ "billing_country" => $invoice->billing->country,
486
  "billing_phone" => $invoice->billing->phone,
487
  "cardtype" => $invoice->cardtype,
488
  "accountnumber" => hideCardNumber($invoice->accountnumber),
489
  "expirationmonth" => $invoice->expirationmonth,
490
  "expirationyear" => $invoice->expirationyear,
491
+ "login_link" => wp_login_url(pmpro_url("billing"))
492
  );
493
+ $this->data["billing_address"] = pmpro_formatAddress($invoice->billing->name,
494
+ $invoice->billing->street,
495
+ "", //address 2
496
+ $invoice->billing->city,
497
+ $invoice->billing->state,
498
+ $invoice->billing->zip,
499
+ $invoice->billing->country,
500
+ $invoice->billing->phone);
501
 
502
  return $this->sendEmail();
503
+ }
504
 
505
  function sendBillingFailureAdminEmail($email, $invoice = NULL)
506
  {
510
  $user = get_userdata($invoice->user_id);
511
 
512
  $this->email = $email;
513
+ $this->subject = sprintf(__("Membership Payment Failed For %s at %s", "pmpro"), $user->display_name, get_option("blogname"));
514
  $this->template = "billing_failure_admin";
515
 
516
  $this->data = array(
517
  "subject" => $this->subject,
518
  "name" => "Admin",
519
+ "user_login" => $user->user_login,
520
  "sitename" => get_option("blogname"),
521
+ "siteemail" => pmpro_getOption("from_email"),
522
+ "membership_id" => $user->membership_level->id,
523
  "membership_level_name" => $user->membership_level->name,
524
  "display_name" => $user->display_name,
525
  "user_email" => $user->user_email,
528
  "billing_city" => $invoice->billing->city,
529
  "billing_state" => $invoice->billing->state,
530
  "billing_zip" => $invoice->billing->zip,
531
+ "billing_country" => $invoice->billing->country,
532
  "billing_phone" => $invoice->billing->phone,
533
  "cardtype" => $invoice->cardtype,
534
  "accountnumber" => hideCardNumber($invoice->accountnumber),
535
  "expirationmonth" => $invoice->expirationmonth,
536
  "expirationyear" => $invoice->expirationyear,
537
+ "login_link" => wp_login_url(pmpro_url("billing"))
538
  );
539
+ $this->data["billing_address"] = pmpro_formatAddress($invoice->billing->name,
540
+ $invoice->billing->street,
541
+ "", //address 2
542
+ $invoice->billing->city,
543
+ $invoice->billing->state,
544
+ $invoice->billing->zip,
545
+ $invoice->billing->country,
546
+ $invoice->billing->phone);
547
+ return $this->sendEmail();
548
+ }
549
+
550
+ function sendCreditCardExpiringEmail($user = NULL, $invoice = NULL)
551
+ {
552
+ global $current_user;
553
+ if(!$user)
554
+ $user = $current_user;
555
+
556
+ if(!$user || !$invoice)
557
+ return false;
558
+
559
+ $this->email = $user->user_email;
560
+ $this->subject = sprintf(__("Credit Card on File Expiring Soon at %s", "pmpro"), get_option("blogname"));
561
+ $this->template = "credit_card_expiring";
562
+
563
+ $this->data = array(
564
+ "subject" => $this->subject,
565
+ "name" => $user->display_name,
566
+ "user_login" => $user->user_login,
567
+ "sitename" => get_option("blogname"),
568
+ "siteemail" => pmpro_getOption("from_email"),
569
+ "membership_id" => $user->membership_level->id,
570
+ "membership_level_name" => $user->membership_level->name,
571
+ "display_name" => $user->display_name,
572
+ "user_email" => $user->user_email,
573
+ "billing_name" => $invoice->billing->name,
574
+ "billing_street" => $invoice->billing->street,
575
+ "billing_city" => $invoice->billing->city,
576
+ "billing_state" => $invoice->billing->state,
577
+ "billing_zip" => $invoice->billing->zip,
578
+ "billing_country" => $invoice->billing->country,
579
+ "billing_phone" => $invoice->billing->phone,
580
+ "cardtype" => $invoice->cardtype,
581
+ "accountnumber" => hideCardNumber($invoice->accountnumber),
582
+ "expirationmonth" => $invoice->expirationmonth,
583
+ "expirationyear" => $invoice->expirationyear,
584
+ "login_link" => wp_login_url(pmpro_url("billing"))
585
+ );
586
+ $this->data["billing_address"] = pmpro_formatAddress($invoice->billing->name,
587
+ $invoice->billing->street,
588
+ "", //address 2
589
+ $invoice->billing->city,
590
+ $invoice->billing->state,
591
+ $invoice->billing->zip,
592
+ $invoice->billing->country,
593
+ $invoice->billing->phone);
594
 
595
  return $this->sendEmail();
596
  }
597
 
598
  function sendInvoiceEmail($user = NULL, $invoice = NULL)
599
  {
600
+ global $wpdb, $current_user;
601
  if(!$user)
602
  $user = $current_user;
603
 
605
  return false;
606
 
607
  $this->email = $user->user_email;
608
+ $this->subject = sprintf(__("INVOICE for %s membership", "pmpro"), get_option("blogname"));
609
  $this->template = "invoice";
610
 
611
  $this->data = array(
612
  "subject" => $this->subject,
613
  "name" => $user->display_name,
614
+ "user_login" => $user->user_login,
615
  "sitename" => get_option("blogname"),
616
+ "siteemail" => pmpro_getOption("from_email"),
617
+ "membership_id" => $user->membership_level->id,
618
  "membership_level_name" => $user->membership_level->name,
619
  "display_name" => $user->display_name,
620
  "user_email" => $user->user_email,
621
+ "invoice_id" => $invoice->code,
622
+ "invoice_total" => pmpro_formatPrice($invoice->total),
623
+ "invoice_date" => date(get_option('date_format'), $invoice->timestamp),
624
  "billing_name" => $invoice->billing->name,
625
  "billing_street" => $invoice->billing->street,
626
  "billing_city" => $invoice->billing->city,
627
  "billing_state" => $invoice->billing->state,
628
  "billing_zip" => $invoice->billing->zip,
629
+ "billing_country" => $invoice->billing->country,
630
  "billing_phone" => $invoice->billing->phone,
631
  "cardtype" => $invoice->cardtype,
632
  "accountnumber" => hideCardNumber($invoice->accountnumber),
633
  "expirationmonth" => $invoice->expirationmonth,
634
  "expirationyear" => $invoice->expirationyear,
635
+ "login_link" => wp_login_url(pmpro_url("account")),
636
+ "invoice_link" => wp_login_url(pmpro_url("invoice", "?invoice=" . $invoice->code)
637
+ ));
638
+ $this->data["billing_address"] = pmpro_formatAddress($invoice->billing->name,
639
+ $invoice->billing->street,
640
+ "", //address 2
641
+ $invoice->billing->city,
642
+ $invoice->billing->state,
643
+ $invoice->billing->zip,
644
+ $invoice->billing->country,
645
+ $invoice->billing->phone);
646
+
647
+ if($invoice->getDiscountCode())
648
+ $this->data["discount_code"] = "<p>" . __("Discount Code", "pmpro") . ": " . $invoice->discount_code . "</p>\n";
649
+ else
650
+ $this->data["discount_code"] = "";
651
 
652
+ $enddate = $wpdb->get_var("SELECT UNIX_TIMESTAMP(enddate) FROM $wpdb->pmpro_memberships_users WHERE user_id = '" . $user->ID . "' AND status = 'active' LIMIT 1");
653
+ if($enddate)
654
+ $this->data["membership_expiration"] = "<p>" . sprintf(__("This membership will expire on %s.", "pmpro"), date(get_option('date_format'), $enddate)) . "</p>\n";
655
+ else
656
+ $this->data["membership_expiration"] = "";
657
+
658
  return $this->sendEmail();
659
  }
660
 
661
+ function sendTrialEndingEmail($user = NULL)
662
+ {
663
+ global $current_user, $wpdb;
664
+ if(!$user)
665
+ $user = $current_user;
666
+
667
+ if(!$user)
668
+ return false;
669
+
670
+ //make sure we have the current membership level data
671
+ /*$user->membership_level = $wpdb->get_row("SELECT l.id AS ID, l.name AS name, UNIX_TIMESTAMP(mu.startdate) as startdate, mu.billing_amount, mu.cycle_number, mu.cycle_period, mu.trial_amount, mu.trial_limit
672
+ FROM {$wpdb->pmpro_membership_levels} AS l
673
+ JOIN {$wpdb->pmpro_memberships_users} AS mu ON (l.id = mu.membership_id)
674
+ WHERE mu.user_id = " . $user->ID . "
675
+ LIMIT 1");*/
676
+ $user->membership_level = pmpro_getMembershipLevelForUser($user->ID);
677
+
678
+ $this->email = $user->user_email;
679
+ $this->subject = sprintf(__("Your trial at %s is ending soon", "pmpro"), get_option("blogname"));
680
+ $this->template = "trial_ending";
681
+ $this->data = array(
682
+ "subject" => $this->subject,
683
+ "name" => $user->display_name,
684
+ "user_login" => $user->user_login,
685
+ "sitename" => get_option("blogname"),
686
+ "membership_id" => $user->membership_level->id,
687
+ "membership_level_name" => $user->membership_level->name,
688
+ "siteemail" => pmpro_getOption("from_email"),
689
+ "login_link" => wp_login_url(),
690
+ "display_name" => $user->display_name,
691
+ "user_email" => $user->user_email,
692
+ "billing_amount" => pmpro_formatPrice($user->membership_level->billing_amount),
693
+ "cycle_number" => $user->membership_level->cycle_number,
694
+ "cycle_period" => $user->membership_level->cycle_period,
695
+ "trial_amount" => pmpro_formatPrice($user->membership_level->trial_amount),
696
+ "trial_limit" => $user->membership_level->trial_limit,
697
+ "trial_end" => date(get_option('date_format'), strtotime(date("m/d/Y", $user->membership_level->startdate) . " + " . $user->membership_level->trial_limit . " " . $user->membership_level->cycle_period), current_time("timestamp"))
698
+ );
699
+
700
+ return $this->sendEmail();
701
+ }
702
+
703
+ function sendMembershipExpiredEmail($user = NULL)
704
+ {
705
+ global $current_user, $wpdb;
706
+ if(!$user)
707
+ $user = $current_user;
708
+
709
+ if(!$user)
710
+ return false;
711
+
712
+ $this->email = $user->user_email;
713
+ $this->subject = sprintf(__("Your membership at %s has ended", "pmpro"), get_option("blogname"));
714
+ $this->template = "membership_expired";
715
+ $this->data = array("subject" => $this->subject, "name" => $user->display_name, "user_login" => $user->user_login, "sitename" => get_option("blogname"), "siteemail" => pmpro_getOption("from_email"), "login_link" => wp_login_url(), "display_name" => $user->display_name, "user_email" => $user->user_email, "levels_link" => pmpro_url("levels"));
716
+
717
+ return $this->sendEmail();
718
+ }
719
+
720
+ function sendMembershipExpiringEmail($user = NULL)
721
  {
722
  global $current_user, $wpdb;
723
  if(!$user)
727
  return false;
728
 
729
  //make sure we have the current membership level data
730
+ /*$user->membership_level = $wpdb->get_row("SELECT l.id AS ID, l.name AS name, UNIX_TIMESTAMP(mu.enddate) as enddate
731
  FROM {$wpdb->pmpro_membership_levels} AS l
732
  JOIN {$wpdb->pmpro_memberships_users} AS mu ON (l.id = mu.membership_id)
733
  WHERE mu.user_id = " . $user->ID . "
734
+ LIMIT 1");*/
735
+ $user->membership_level = pmpro_getMembershipLevelForUser($user->ID);
736
 
737
  $this->email = $user->user_email;
738
+ $this->subject = sprintf(__("Your membership at %s will end soon", "pmpro"), get_option("blogname"));
739
+ $this->template = "membership_expiring";
740
+ $this->data = array("subject" => $this->subject, "name" => $user->display_name, "user_login" => $user->user_login, "sitename" => get_option("blogname"), "membership_id" => $user->membership_level->id, "membership_level_name" => $user->membership_level->name, "siteemail" => pmpro_getOption("from_email"), "login_link" => wp_login_url(), "enddate" => date(get_option('date_format'), $user->membership_level->enddate), "display_name" => $user->display_name, "user_email" => $user->user_email);
741
+
742
+ return $this->sendEmail();
743
+ }
744
+
745
+ function sendAdminChangeEmail($user = NULL)
746
+ {
747
+ global $current_user, $wpdb;
748
+ if(!$user)
749
+ $user = $current_user;
750
+
751
+ if(!$user)
752
+ return false;
753
+
754
+ //make sure we have the current membership level data
755
+ $user->membership_level = pmpro_getMembershipLevelForUser($user->ID);
756
+
757
+ $this->email = $user->user_email;
758
+ $this->subject = sprintf(__("Your membership at %s has been changed", "pmpro"), get_option("blogname"));
759
  $this->template = "admin_change";
760
+ $this->data = array("subject" => $this->subject, "name" => $user->display_name, "user_login" => $user->user_login, "sitename" => get_option("blogname"), "membership_id" => $user->membership_level->id, "membership_level_name" => $user->membership_level->name, "siteemail" => pmpro_getOption("from_email"), "login_link" => wp_login_url());
761
  if($user->membership_level->ID)
762
+ $this->data["membership_change"] = sprintf(__("The new level is %s.", "pmpro"), $user->membership_level->name);
763
  else
764
+ $this->data["membership_change"] = __("Your membership has been cancelled", "pmpro");
765
+
766
+ if(!empty($user->membership_level->enddate))
767
+ {
768
+ $this->data["membership_change"] .= ". " . sprintf(__("This membership will expire on %s", "pmpro"), date(get_option('date_format'), $user->membership_level->enddate));
769
+ }
770
+ elseif(!empty($this->expiration_changed))
771
+ {
772
+ $this->data["membership_change"] .= ". " . __("This membership does not expire", "pmpro");
773
+ }
774
+
775
+ return $this->sendEmail();
776
+ }
777
+
778
+ function sendAdminChangeAdminEmail($user = NULL)
779
+ {
780
+ global $current_user, $wpdb;
781
+ if(!$user)
782
+ $user = $current_user;
783
+
784
+ if(!$user)
785
+ return false;
786
+
787
+ //check settings
788
+ $send = pmpro_getOption("email_admin_changes");
789
+ if(empty($send))
790
+ return true; //didn't send, but we also don't want to indicate failure because the settings say to not send
791
+
792
+ //make sure we have the current membership level data
793
+ $user->membership_level = pmpro_getMembershipLevelForUser($user->ID);
794
+
795
+ $this->email = get_bloginfo("admin_email");
796
+ $this->subject = sprintf(__("Membership for %s at %s has been changed", "pmpro"), $user->user_login, get_option("blogname"));
797
+ $this->template = "admin_change_admin";
798
+ $this->data = array("subject" => $this->subject, "name" => $user->display_name, "user_login" => $user->user_login, "sitename" => get_option("blogname"), "membership_level_name" => $user->membership_level->name, "siteemail" => get_bloginfo("admin_email"), "login_link" => wp_login_url());
799
+ if($user->membership_level->ID)
800
+ $this->data["membership_change"] = sprintf(__("The new level is %s. This membership is free", "pmpro"), $user->membership_level->name);
801
+ else
802
+ $this->data["membership_change"] = __("Membership has been cancelled", "pmpro");
803
+
804
+ if(!empty($user->membership_level->enddate))
805
+ {
806
+ $this->data["membership_change"] .= ". " . sprintf(__("This membership will expire on %s", "pmpro"), date(get_option('date_format'), $user->membership_level->enddate));
807
+ }
808
+ elseif(!empty($this->expiration_changed))
809
+ {
810
+ $this->data["membership_change"] .= ". " . __("This membership does not expire", "pmpro");
811
+ }
812
 
813
  return $this->sendEmail();
814
  }
815
  }
 
classes/gateways/class.pmprogateway.php ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //require_once(dirname(__FILE__) . "/class.pmprogateway.php");
3
+ class PMProGateway
4
+ {
5
+ function PMProGateway($gateway = NULL)
6
+ {
7
+ $this->gateway = $gateway;
8
+ return $this->gateway;
9
+ }
10
+
11
+ function process(&$order)
12
+ {
13
+ //check for initial payment
14
+ if(floatval($order->InitialPayment) == 0)
15
+ {
16
+ //auth first, then process
17
+ if($this->authorize($order))
18
+ {
19
+ $this->void($order);
20
+ if(!pmpro_isLevelTrial($order->membership_level))
21
+ {
22
+ //subscription will start today with a 1 period trial
23
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
24
+ $order->TrialBillingPeriod = $order->BillingPeriod;
25
+ $order->TrialBillingFrequency = $order->BillingFrequency;
26
+ $order->TrialBillingCycles = 1;
27
+ $order->TrialAmount = 0;
28
+
29
+ //add a billing cycle to make up for the trial, if applicable
30
+ if(!empty($order->TotalBillingCycles))
31
+ $order->TotalBillingCycles++;
32
+ }
33
+ elseif($order->InitialPayment == 0 && $order->TrialAmount == 0)
34
+ {
35
+ //it has a trial, but the amount is the same as the initial payment, so we can squeeze it in there
36
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
37
+ $order->TrialBillingCycles++;
38
+
39
+ //add a billing cycle to make up for the trial, if applicable
40
+ if($order->TotalBillingCycles)
41
+ $order->TotalBillingCycles++;
42
+ }
43
+ else
44
+ {
45
+ //add a period to the start date to account for the initial payment
46
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $order->BillingFrequency . " " . $order->BillingPeriod, current_time("timestamp"))) . "T0:0:0";
47
+ }
48
+
49
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
50
+ return $this->subscribe($order);
51
+ }
52
+ else
53
+ {
54
+ if(empty($order->error))
55
+ $order->error = __("Unknown error: Authorization failed.", "pmpro");
56
+ return false;
57
+ }
58
+ }
59
+ else
60
+ {
61
+ //charge first payment
62
+ if($this->charge($order))
63
+ {
64
+ //setup recurring billing
65
+ if(pmpro_isLevelRecurring($order->membership_level))
66
+ {
67
+ if(!pmpro_isLevelTrial($order->membership_level))
68
+ {
69
+ //subscription will start today with a 1 period trial
70
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
71
+ $order->TrialBillingPeriod = $order->BillingPeriod;
72
+ $order->TrialBillingFrequency = $order->BillingFrequency;
73
+ $order->TrialBillingCycles = 1;
74
+ $order->TrialAmount = 0;
75
+
76
+ //add a billing cycle to make up for the trial, if applicable
77
+ if(!empty($order->TotalBillingCycles))
78
+ $order->TotalBillingCycles++;
79
+ }
80
+ elseif($order->InitialPayment == 0 && $order->TrialAmount == 0)
81
+ {
82
+ //it has a trial, but the amount is the same as the initial payment, so we can squeeze it in there
83
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
84
+ $order->TrialBillingCycles++;
85
+
86
+ //add a billing cycle to make up for the trial, if applicable
87
+ if(!empty($order->TotalBillingCycles))
88
+ $order->TotalBillingCycles++;
89
+ }
90
+ else
91
+ {
92
+ //add a period to the start date to account for the initial payment
93
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $this->BillingFrequency . " " . $this->BillingPeriod, current_time("timestamp"))) . "T0:0:0";
94
+ }
95
+
96
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
97
+ if($this->subscribe($order))
98
+ {
99
+ return true;
100
+ }
101
+ else
102
+ {
103
+ if($this->void($order))
104
+ {
105
+ if(!$order->error)
106
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
107
+ }
108
+ else
109
+ {
110
+ if(!$order->error)
111
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
112
+
113
+ $order->error .= " " . __("A partial payment was made that we could not void. Please contact the site owner immediately to correct this.", "pmpro");
114
+ }
115
+
116
+ return false;
117
+ }
118
+ }
119
+ else
120
+ {
121
+ //only a one time charge
122
+ $order->status = "success"; //saved on checkout page
123
+ return true;
124
+ }
125
+ }
126
+ else
127
+ {
128
+ if(empty($order->error))
129
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
130
+
131
+ return false;
132
+ }
133
+ }
134
+ }
135
+
136
+ function authorize(&$order)
137
+ {
138
+ //create a code for the order
139
+ if(empty($order->code))
140
+ $order->code = $order->getRandomCode();
141
+
142
+ //simulate a successful authorization
143
+ $order->payment_transaction_id = "TEST" . $order->code;
144
+ $order->updateStatus("authorized");
145
+ return true;
146
+ }
147
+
148
+ function void(&$order)
149
+ {
150
+ //need a transaction id
151
+ if(empty($order->payment_transaction_id))
152
+ return false;
153
+
154
+ //simulate a successful void
155
+ $order->payment_transaction_id = "TEST" . $order->code;
156
+ $order->updateStatus("voided");
157
+ return true;
158
+ }
159
+
160
+ function charge(&$order)
161
+ {
162
+ //create a code for the order
163
+ if(empty($order->code))
164
+ $order->code = $order->getRandomCode();
165
+
166
+ //simulate a successful charge
167
+ $order->payment_transaction_id = "TEST" . $order->code;
168
+ $order->updateStatus("success");
169
+ return true;
170
+ }
171
+
172
+ function subscribe(&$order)
173
+ {
174
+ //create a code for the order
175
+ if(empty($order->code))
176
+ $order->code = $order->getRandomCode();
177
+
178
+ //filter order before subscription. use with care.
179
+ $order = apply_filters("pmpro_subscribe_order", $order, $this);
180
+
181
+ //simulate a successful subscription processing
182
+ $order->status = "success";
183
+ $order->subscription_transaction_id = "TEST" . $order->code;
184
+ return true;
185
+ }
186
+
187
+ function update(&$order)
188
+ {
189
+ //simulate a successful billing update
190
+ return true;
191
+ }
192
+
193
+ function cancel(&$order)
194
+ {
195
+ //require a subscription id
196
+ if(empty($order->subscription_transaction_id))
197
+ return false;
198
+
199
+ //simulate a successful cancel
200
+ $order->updateStatus("cancelled");
201
+ return true;
202
+ }
203
+
204
+ function getSubscriptionStatus(&$order)
205
+ {
206
+ //require a subscription id
207
+ if(empty($order->subscription_transaction_id))
208
+ return false;
209
+
210
+ //this looks different for each gateway, but generally an array of some sort
211
+ return array();
212
+ }
213
+
214
+ function getTransactionStatus(&$order)
215
+ {
216
+ //this looks different for each gateway, but generally an array of some sort
217
+ return array();
218
+ }
219
+ }
220
+ ?>
classes/gateways/class.pmprogateway_authorizenet.php ADDED
@@ -0,0 +1,949 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/class.pmprogateway.php");
3
+ class PMProGateway_authorizenet extends PMProGateway
4
+ {
5
+ function PMProGateway_authorizenet($gateway = NULL)
6
+ {
7
+ $this->gateway = $gateway;
8
+ return $this->gateway;
9
+ }
10
+
11
+ function process(&$order)
12
+ {
13
+ //check for initial payment
14
+ if(floatval($order->InitialPayment) == 0)
15
+ {
16
+ //auth first, then process
17
+ if($this->authorize($order))
18
+ {
19
+ $this->void($order);
20
+ if(!pmpro_isLevelTrial($order->membership_level))
21
+ {
22
+ //subscription will start today with a 1 period trial
23
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
24
+ $order->TrialBillingPeriod = $order->BillingPeriod;
25
+ $order->TrialBillingFrequency = $order->BillingFrequency;
26
+ $order->TrialBillingCycles = 1;
27
+ $order->TrialAmount = 0;
28
+
29
+ //add a billing cycle to make up for the trial, if applicable
30
+ if(!empty($order->TotalBillingCycles))
31
+ $order->TotalBillingCycles++;
32
+ }
33
+ elseif($order->InitialPayment == 0 && $order->TrialAmount == 0)
34
+ {
35
+ //it has a trial, but the amount is the same as the initial payment, so we can squeeze it in there
36
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
37
+ $order->TrialBillingCycles++;
38
+
39
+ //add a billing cycle to make up for the trial, if applicable
40
+ if(!empty($order->TotalBillingCycles))
41
+ $order->TotalBillingCycles++;
42
+ }
43
+ else
44
+ {
45
+ //add a period to the start date to account for the initial payment
46
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $order->BillingFrequency . " " . $order->BillingPeriod, current_time("timestamp"))) . "T0:0:0";
47
+ }
48
+
49
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
50
+ return $this->subscribe($order);
51
+ }
52
+ else
53
+ {
54
+ if(empty($order->error))
55
+ $order->error = __("Unknown error: Authorization failed.", "pmpro");
56
+ return false;
57
+ }
58
+ }
59
+ else
60
+ {
61
+ //charge first payment
62
+ if($this->charge($order))
63
+ {
64
+ //setup recurring billing
65
+ if(pmpro_isLevelRecurring($order->membership_level))
66
+ {
67
+ if(!pmpro_isLevelTrial($order->membership_level))
68
+ {
69
+ //subscription will start today with a 1 period trial
70
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
71
+ $order->TrialBillingPeriod = $order->BillingPeriod;
72
+ $order->TrialBillingFrequency = $order->BillingFrequency;
73
+ $order->TrialBillingCycles = 1;
74
+ $order->TrialAmount = 0;
75
+
76
+ //add a billing cycle to make up for the trial, if applicable
77
+ if(!empty($order->TotalBillingCycles))
78
+ $order->TotalBillingCycles++;
79
+ }
80
+ elseif($order->InitialPayment == 0 && $order->TrialAmount == 0)
81
+ {
82
+ //it has a trial, but the amount is the same as the initial payment, so we can squeeze it in there
83
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
84
+ $order->TrialBillingCycles++;
85
+
86
+ //add a billing cycle to make up for the trial, if applicable
87
+ if(!empty($order->TotalBillingCycles))
88
+ $order->TotalBillingCycles++;
89
+ }
90
+ else
91
+ {
92
+ //add a period to the start date to account for the initial payment
93
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $order->BillingFrequency . " " . $order->BillingPeriod, current_time("timestamp"))) . "T0:0:0";
94
+ }
95
+
96
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
97
+ if($this->subscribe($order))
98
+ {
99
+ return true;
100
+ }
101
+ else
102
+ {
103
+ if($this->void($order))
104
+ {
105
+ if(!$order->error)
106
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
107
+ }
108
+ else
109
+ {
110
+ if(!$order->error)
111
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
112
+ $order->error .= " " . __("A partial payment was made that we could not void. Please contact the site owner immediately to correct this.", "pmpro");
113
+ }
114
+
115
+ return false;
116
+ }
117
+ }
118
+ else
119
+ {
120
+ //only a one time charge
121
+ $order->status = "success"; //saved on checkout page
122
+ return true;
123
+ }
124
+ }
125
+ else
126
+ {
127
+ if(empty($order->error))
128
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
129
+
130
+ return false;
131
+ }
132
+ }
133
+ }
134
+
135
+ function authorize(&$order)
136
+ {
137
+ if(empty($order->code))
138
+ $order->code = $order->getRandomCode();
139
+
140
+ if(empty($order->gateway_environment))
141
+ $gateway_environment = pmpro_getOption("gateway_environment");
142
+ else
143
+ $gateway_environment = $order->gateway_environment;
144
+ if($gateway_environment == "live")
145
+ $host = "secure.authorize.net";
146
+ else
147
+ $host = "test.authorize.net";
148
+
149
+ $path = "/gateway/transact.dll";
150
+ $post_url = "https://" . $host . $path;
151
+
152
+ $post_url = apply_filters("pmpro_authorizenet_post_url", $post_url, $gateway_environment);
153
+
154
+ //what amount to authorize? just $1 to test
155
+ $amount = "1.00";
156
+
157
+ //combine address
158
+ $address = $order->Address1;
159
+ if(!empty($order->Address2))
160
+ $address .= "\n" . $order->Address2;
161
+
162
+ //customer stuff
163
+ $customer_email = $order->Email;
164
+ $customer_phone = $order->billing->phone;
165
+
166
+ if(!isset($order->membership_level->name))
167
+ $order->membership_level->name = "";
168
+
169
+ $post_values = array(
170
+
171
+ // the API Login ID and Transaction Key must be replaced with valid values
172
+ "x_login" => pmpro_getOption("loginname"),
173
+ "x_tran_key" => pmpro_getOption("transactionkey"),
174
+
175
+ "x_version" => "3.1",
176
+ "x_delim_data" => "TRUE",
177
+ "x_delim_char" => "|",
178
+ "x_relay_response" => "FALSE",
179
+
180
+ "x_type" => "AUTH_ONLY",
181
+ "x_method" => "CC",
182
+ "x_card_type" => $order->cardtype,
183
+ "x_card_num" => $order->accountnumber,
184
+ "x_exp_date" => $order->ExpirationDate,
185
+
186
+ "x_amount" => $amount,
187
+ "x_description" => $order->membership_level->name . " " . __("Membership", "pmpro"),
188
+
189
+ "x_first_name" => $order->FirstName,
190
+ "x_last_name" => $order->LastName,
191
+ "x_address" => $address,
192
+ "x_city" => $order->billing->city,
193
+ "x_state" => $order->billing->state,
194
+ "x_zip" => $order->billing->zip,
195
+ "x_country" => $order->billing->country,
196
+ "x_invoice_num" => $order->code,
197
+ "x_phone" => $customer_phone,
198
+ "x_email" => $order->Email
199
+ // Additional fields can be added here as outlined in the AIM integration
200
+ // guide at: http://developer.authorize.net
201
+ );
202
+
203
+ if(!empty($order->CVV2))
204
+ $post_values["x_card_code"] = $order->CVV2;
205
+
206
+ // This section takes the input fields and converts them to the proper format
207
+ // for an http post. For example: "x_login=username&x_tran_key=a1B2c3D4"
208
+ $post_string = "";
209
+ foreach( $post_values as $key => $value )
210
+ { $post_string .= "$key=" . urlencode( str_replace("#", "%23", $value) ) . "&"; }
211
+ $post_string = rtrim( $post_string, "& " );
212
+
213
+ //curl
214
+ $request = curl_init($post_url); // initiate curl object
215
+ curl_setopt($request, CURLOPT_HEADER, 0); // set to 0 to eliminate header info from response
216
+ curl_setopt($request, CURLOPT_RETURNTRANSFER, 1); // Returns response data instead of TRUE(1)
217
+ curl_setopt($request, CURLOPT_POSTFIELDS, $post_string); // use HTTP POST to send form data
218
+ curl_setopt($request, CURLOPT_SSL_VERIFYPEER, FALSE); // uncomment this line if you get no gateway response.
219
+ $post_response = curl_exec($request); // execute curl post and store results in $post_response
220
+ // additional options may be required depending upon your server configuration
221
+ // you can find documentation on curl options at http://www.php.net/curl_setopt
222
+ curl_close ($request); // close curl object
223
+
224
+ // This line takes the response and breaks it into an array using the specified delimiting character
225
+ $response_array = explode($post_values["x_delim_char"],$post_response);
226
+
227
+ if($response_array[0] == 1)
228
+ {
229
+ $order->payment_transaction_id = $response_array[6];
230
+ $order->updateStatus("authorized");
231
+
232
+ return true;
233
+ }
234
+ else
235
+ {
236
+ //$order->status = "error";
237
+ $order->errorcode = $response_array[2];
238
+ $order->error = $response_array[3];
239
+ $order->shorterror = $response_array[3];
240
+ return false;
241
+ }
242
+ }
243
+
244
+ function void(&$order)
245
+ {
246
+ if(empty($order->payment_transaction_id))
247
+ return false;
248
+
249
+ if(empty($order->gateway_environment))
250
+ $gateway_environment = pmpro_getOption("gateway_environment");
251
+ else
252
+ $gateway_environment = $order->gateway_environment;
253
+ if($gateway_environment == "live")
254
+ $host = "secure.authorize.net";
255
+ else
256
+ $host = "test.authorize.net";
257
+
258
+ $path = "/gateway/transact.dll";
259
+ $post_url = "https://" . $host . $path;
260
+
261
+ $post_url = apply_filters("pmpro_authorizenet_post_url", $post_url, $gateway_environment);
262
+
263
+ $post_values = array(
264
+
265
+ // the API Login ID and Transaction Key must be replaced with valid values
266
+ "x_login" => pmpro_getOption("loginname"),
267
+ "x_tran_key" => pmpro_getOption("transactionkey"),
268
+
269
+ "x_version" => "3.1",
270
+ "x_delim_data" => "TRUE",
271
+ "x_delim_char" => "|",
272
+ "x_relay_response" => "FALSE",
273
+
274
+ "x_type" => "VOID",
275
+ "x_trans_id" => $order->payment_transaction_id
276
+ // Additional fields can be added here as outlined in the AIM integration
277
+ // guide at: http://developer.authorize.net
278
+ );
279
+
280
+ // This section takes the input fields and converts them to the proper format
281
+ // for an http post. For example: "x_login=username&x_tran_key=a1B2c3D4"
282
+ $post_string = "";
283
+ foreach( $post_values as $key => $value )
284
+ { $post_string .= "$key=" . urlencode( str_replace("#", "%23", $value) ) . "&"; }
285
+ $post_string = rtrim( $post_string, "& " );
286
+
287
+ //curl
288
+ $request = curl_init($post_url); // initiate curl object
289
+ curl_setopt($request, CURLOPT_HEADER, 0); // set to 0 to eliminate header info from response
290
+ curl_setopt($request, CURLOPT_RETURNTRANSFER, 1); // Returns response data instead of TRUE(1)
291
+ curl_setopt($request, CURLOPT_POSTFIELDS, $post_string); // use HTTP POST to send form data
292
+ curl_setopt($request, CURLOPT_SSL_VERIFYPEER, FALSE); // uncomment this line if you get no gateway response.
293
+ $post_response = curl_exec($request); // execute curl post and store results in $post_response
294
+ // additional options may be required depending upon your server configuration
295
+ // you can find documentation on curl options at http://www.php.net/curl_setopt
296
+ curl_close ($request); // close curl object
297
+
298
+ // This line takes the response and breaks it into an array using the specified delimiting character
299
+ $response_array = explode($post_values["x_delim_char"],$post_response);
300
+ if($response_array[0] == 1)
301
+ {
302
+ $order->payment_transaction_id = $response_array[4];
303
+ $order->updateStatus("voided");
304
+ return true;
305
+ }
306
+ else
307
+ {
308
+ //$order->status = "error";
309
+ $order->errorcode = $response_array[2];
310
+ $order->error = $response_array[3];
311
+ $order->shorterror = $response_array[3];
312
+ return false;
313
+ }
314
+ }
315
+
316
+ function charge(&$order)
317
+ {
318
+ if(empty($order->code))
319
+ $order->code = $order->getRandomCode();
320
+
321
+ if(!empty($order->gateway_environment))
322
+ $gateway_environment = $order->gateway_environment;
323
+ if(empty($gateway_environment))
324
+ $gateway_environment = pmpro_getOption("gateway_environment");
325
+ if($gateway_environment == "live")
326
+ $host = "secure.authorize.net";
327
+ else
328
+ $host = "test.authorize.net";
329
+
330
+ $path = "/gateway/transact.dll";
331
+ $post_url = "https://" . $host . $path;
332
+
333
+ $post_url = apply_filters("pmpro_authorizenet_post_url", $post_url, $gateway_environment);
334
+
335
+ //what amount to charge?
336
+ $amount = $order->InitialPayment;
337
+
338
+ //tax
339
+ $order->subtotal = $amount;
340
+ $tax = $order->getTax(true);
341
+ $amount = round((float)$order->subtotal + (float)$tax, 2);
342
+
343
+ //combine address
344
+ $address = $order->Address1;
345
+ if(!empty($order->Address2))
346
+ $address .= "\n" . $order->Address2;
347
+
348
+ //customer stuff
349
+ $customer_email = $order->Email;
350
+ $customer_phone = $order->billing->phone;
351
+
352
+ if(!isset($order->membership_level->name))
353
+ $order->membership_level->name = "";
354
+
355
+ $post_values = array(
356
+
357
+ // the API Login ID and Transaction Key must be replaced with valid values
358
+ "x_login" => pmpro_getOption("loginname"),
359
+ "x_tran_key" => pmpro_getOption("transactionkey"),
360
+
361
+ "x_version" => "3.1",
362
+ "x_delim_data" => "TRUE",
363
+ "x_delim_char" => "|",
364
+ "x_relay_response" => "FALSE",
365
+
366
+ "x_type" => "AUTH_CAPTURE",
367
+ "x_method" => "CC",
368
+ "x_card_type" => $order->cardtype,
369
+ "x_card_num" => $order->accountnumber,
370
+ "x_exp_date" => $order->ExpirationDate,
371
+
372
+ "x_amount" => $amount,
373
+ "x_tax" => $tax,
374
+ "x_description" => $order->membership_level->name . " Membership",
375
+
376
+ "x_first_name" => $order->FirstName,
377
+ "x_last_name" => $order->LastName,
378
+ "x_address" => $address,
379
+ "x_city" => $order->billing->city,
380
+ "x_state" => $order->billing->state,
381
+ "x_zip" => $order->billing->zip,
382
+ "x_country" => $order->billing->country,
383
+ "x_invoice_num" => $order->code,
384
+ "x_phone" => $customer_phone,
385
+ "x_email" => $order->Email
386
+
387
+ // Additional fields can be added here as outlined in the AIM integration
388
+ // guide at: http://developer.authorize.net
389
+ );
390
+
391
+ if(!empty($order->CVV2))
392
+ $post_values["x_card_code"] = $order->CVV2;
393
+
394
+ // This section takes the input fields and converts them to the proper format
395
+ // for an http post. For example: "x_login=username&x_tran_key=a1B2c3D4"
396
+ $post_string = "";
397
+ foreach( $post_values as $key => $value )
398
+ { $post_string .= "$key=" . urlencode( str_replace("#", "%23", $value) ) . "&"; }
399
+ $post_string = rtrim( $post_string, "& " );
400
+
401
+ //curl
402
+ $request = curl_init($post_url); // initiate curl object
403
+ curl_setopt($request, CURLOPT_HEADER, 0); // set to 0 to eliminate header info from response
404
+ curl_setopt($request, CURLOPT_RETURNTRANSFER, 1); // Returns response data instead of TRUE(1)
405
+ curl_setopt($request, CURLOPT_POSTFIELDS, $post_string); // use HTTP POST to send form data
406
+ curl_setopt($request, CURLOPT_SSL_VERIFYPEER, FALSE); // uncomment this line if you get no gateway response.
407
+ $post_response = curl_exec($request); // execute curl post and store results in $post_response
408
+ // additional options may be required depending upon your server configuration
409
+ // you can find documentation on curl options at http://www.php.net/curl_setopt
410
+ curl_close ($request); // close curl object
411
+
412
+ // This line takes the response and breaks it into an array using the specified delimiting character
413
+ $response_array = explode($post_values["x_delim_char"],$post_response);
414
+ if($response_array[0] == 1)
415
+ {
416
+ $order->payment_transaction_id = $response_array[6];
417
+ $order->updateStatus("success");
418
+ return true;
419
+ }
420
+ else
421
+ {
422
+ //$order->status = "error";
423
+ $order->errorcode = $response_array[2];
424
+ $order->error = $response_array[3];
425
+ $order->shorterror = $response_array[3];
426
+ return false;
427
+ }
428
+ }
429
+
430
+ function subscribe(&$order)
431
+ {
432
+ //define variables to send
433
+
434
+ if(empty($order->code))
435
+ $order->code = $order->getRandomCode();
436
+
437
+ //filter order before subscription. use with care.
438
+ $order = apply_filters("pmpro_subscribe_order", $order, $this);
439
+
440
+ if(!empty($order->gateway_environment))
441
+ $gateway_environment = $order->gateway_environment;
442
+ if(empty($gateway_environment))
443
+ $gateway_environment = pmpro_getOption("gateway_environment");
444
+ if($gateway_environment == "live")
445
+ $host = "api.authorize.net";
446
+ else
447
+ $host = "apitest.authorize.net";
448
+
449
+ $path = "/xml/v1/request.api";
450
+
451
+ $loginname = pmpro_getOption("loginname");
452
+ $transactionkey = pmpro_getOption("transactionkey");
453
+
454
+ $amount = $order->PaymentAmount;
455
+ $refId = $order->code;
456
+ $name = $order->membership_name;
457
+ $length = (int)$order->BillingFrequency;
458
+
459
+ if($order->BillingPeriod == "Month")
460
+ $unit = "months";
461
+ elseif($order->BillingPeriod == "Day")
462
+ $unit = "days";
463
+ elseif($order->BillingPeriod == "Year" && $order->BillingFrequency == 1)
464
+ {
465
+ $unit = "months";
466
+ $length = 12;
467
+ }
468
+ elseif($order->BillingPeriod == "Week")
469
+ {
470
+ $unit = "days";
471
+ $length = $length * 7; //converting weeks to days
472
+ }
473
+ else
474
+ return false; //authorize.net only supports months and days
475
+
476
+ $startDate = substr($order->ProfileStartDate, 0, 10);
477
+ if(!empty($order->TotalBillingCycles))
478
+ $totalOccurrences = (int)$order->TotalBillingCycles;
479
+ if(empty($totalOccurrences))
480
+ $totalOccurrences = 9999;
481
+ if(isset($order->TrialBillingCycles))
482
+ $trialOccurrences = (int)$order->TrialBillingCycles;
483
+ else
484
+ $trialOccurrences = 0;
485
+ if(isset($order->TrialAmount))
486
+ $trialAmount = $order->TrialAmount;
487
+ else
488
+ $trialAmount = NULL;
489
+
490
+ //taxes
491
+ $amount_tax = $order->getTaxForPrice($amount);
492
+ $trial_tax = $order->getTaxForPrice($trialAmount);
493
+
494
+ $amount = round((float)$amount + (float)$amount_tax, 2);
495
+ $trialAmount = round((float)$trialAmount + (float)$trial_tax, 2);
496
+
497
+ //authorize.net doesn't support different periods between trial and actual
498
+
499
+ if(!empty($order->TrialBillingPeriod) && $order->TrialBillingPeriod != $order->BillingPeriod)
500
+ {
501
+ echo "F";
502
+ return false;
503
+ }
504
+
505
+ $cardNumber = $order->accountnumber;
506
+ $expirationDate = $order->ExpirationDate_YdashM;
507
+ $cardCode = $order->CVV2;
508
+
509
+ $firstName = $order->FirstName;
510
+ $lastName = $order->LastName;
511
+
512
+ //do address stuff then?
513
+ $address = $order->Address1;
514
+ if(!empty($order->Address2))
515
+ $address .= "\n" . $order->Address2;
516
+ $city = $order->billing->city;
517
+ $state = $order->billing->state;
518
+ $zip = $order->billing->zip;
519
+ $country = $order->billing->country;
520
+
521
+ //customer stuff
522
+ $customer_email = $order->Email;
523
+ if(strpos($order->billing->phone, "+") === false)
524
+ $customer_phone = $order->billing->phone;
525
+ else
526
+ $customer_phone = "";
527
+
528
+ //make sure the phone is in an okay format
529
+ $customer_phone = preg_replace("/[^0-9]/", "", $customer_phone);
530
+ if(strlen($customer_phone) > 10)
531
+ $customer_phone = "";
532
+
533
+ //build xml to post
534
+ $this->content =
535
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>" .
536
+ "<ARBCreateSubscriptionRequest xmlns=\"AnetApi/xml/v1/schema/AnetApiSchema.xsd\">" .
537
+ "<merchantAuthentication>".
538
+ "<name>" . $loginname . "</name>".
539
+ "<transactionKey>" . $transactionkey . "</transactionKey>".
540
+ "</merchantAuthentication>".
541
+ "<refId><![CDATA[" . substr($refId, 0, 20) . "]]></refId>".
542
+ "<subscription>".
543
+ "<name><![CDATA[" . substr($name, 0, 50) . "]]></name>".
544
+ "<paymentSchedule>".
545
+ "<interval>".
546
+ "<length>". $length ."</length>".
547
+ "<unit>". $unit ."</unit>".
548
+ "</interval>".
549
+ "<startDate>" . $startDate . "</startDate>".
550
+ "<totalOccurrences>". $totalOccurrences . "</totalOccurrences>";
551
+ if(!empty($trialOccurrences))
552
+ $this->content .=
553
+ "<trialOccurrences>". $trialOccurrences . "</trialOccurrences>";
554
+ $this->content .=
555
+ "</paymentSchedule>".
556
+ "<amount>". $amount ."</amount>";
557
+ if(!empty($trialOccurrences))
558
+ $this->content .=
559
+ "<trialAmount>" . $trialAmount . "</trialAmount>";
560
+ $this->content .=
561
+ "<payment>".
562
+ "<creditCard>".
563
+ "<cardNumber>" . $cardNumber . "</cardNumber>".
564
+ "<expirationDate>" . $expirationDate . "</expirationDate>";
565
+ if(!empty($cardCode))
566
+ $this->content .= "<cardCode>" . $cardCode . "</cardCode>";
567
+ $this->content .=
568
+ "</creditCard>".
569
+ "</payment>".
570
+ "<order><invoiceNumber>" . substr($order->code, 0, 20) . "</invoiceNumber></order>".
571
+ "<customer>".
572
+ "<email>". substr($customer_email, 0, 255) . "</email>".
573
+ "<phoneNumber>". substr($customer_phone, 0, 25) . "</phoneNumber>".
574
+ "</customer>".
575
+ "<billTo>".
576
+ "<firstName><![CDATA[". substr($firstName, 0, 50) . "]]></firstName>".
577
+ "<lastName><![CDATA[" . substr($lastName, 0, 50) . "]]></lastName>".
578
+ "<address><![CDATA[". substr($address, 0, 60) . "]]></address>".
579
+ "<city><![CDATA[" . substr($city, 0, 40) . "]]></city>".
580
+ "<state>". substr($state, 0, 2) . "</state>".
581
+ "<zip>" . substr($zip, 0, 20) . "</zip>".
582
+ "<country>". substr($country, 0, 60) . "</country>".
583
+ "</billTo>".
584
+ "</subscription>".
585
+ "</ARBCreateSubscriptionRequest>";
586
+
587
+ //send the xml via curl
588
+ $this->response = $this->send_request_via_curl($host,$path,$this->content);
589
+ //if curl is unavilable you can try using fsockopen
590
+ /*
591
+ $response = send_request_via_fsockopen($host,$path,$content);
592
+ */
593
+
594
+ if(!empty($this->response)) {
595
+ list ($refId, $resultCode, $code, $text, $subscriptionId) = $this->parse_return($this->response);
596
+ if($resultCode == "Ok")
597
+ {
598
+ $order->status = "success"; //saved on checkout page
599
+ $order->subscription_transaction_id = $subscriptionId;
600
+ return true;
601
+ }
602
+ else
603
+ {
604
+ $order->status = "error";
605
+ $order->errorcode = $code;
606
+ $order->error = $text;
607
+ $order->shorterror = $text;
608
+ return false;
609
+ }
610
+ } else {
611
+ $order->status = "error";
612
+ $order->error = "Could not connect to Authorize.net";
613
+ $order->shorterror = "Could not connect to Authorize.net";
614
+ return false;
615
+ }
616
+ }
617
+
618
+ function update(&$order)
619
+ {
620
+ //define variables to send
621
+ $gateway_environment = $order->gateway_environment;
622
+ if(empty($gateway_environment))
623
+ $gateway_environment = pmpro_getOption("gateway_environment");
624
+ if($gateway_environment == "live")
625
+ $host = "api.authorize.net";
626
+ else
627
+ $host = "apitest.authorize.net";
628
+
629
+ $path = "/xml/v1/request.api";
630
+
631
+ $loginname = pmpro_getOption("loginname");
632
+ $transactionkey = pmpro_getOption("transactionkey");
633
+
634
+ //$amount = $order->PaymentAmount;
635
+ $refId = $order->code;
636
+ $subscriptionId = $order->subscription_transaction_id;
637
+
638
+ $cardNumber = $order->accountnumber;
639
+ $expirationDate = $order->ExpirationDate_YdashM;
640
+ $cardCode = $order->CVV2;
641
+
642
+ $firstName = $order->FirstName;
643
+ $lastName = $order->LastName;
644
+
645
+ //do address stuff then?
646
+ $address = $order->Address1;
647
+ if(!empty($order->Address2))
648
+ $address .= "\n" . $order->Address2;
649
+ $city = $order->billing->city;
650
+ $state = $order->billing->state;
651
+ $zip = $order->billing->zip;
652
+ $country = $order->billing->country;
653
+
654
+ //customer stuff
655
+ $customer_email = $order->Email;
656
+ if(strpos($order->billing->phone, "+") === false)
657
+ $customer_phone = $order->billing->phone;
658
+
659
+
660
+ //build xml to post
661
+ $this->content =
662
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>" .
663
+ "<ARBUpdateSubscriptionRequest xmlns=\"AnetApi/xml/v1/schema/AnetApiSchema.xsd\">".
664
+ "<merchantAuthentication>".
665
+ "<name><![CDATA[" . $loginname . "]]></name>".
666
+ "<transactionKey>" . $transactionkey . "</transactionKey>".
667
+ "</merchantAuthentication>".
668
+ "<refId>" . substr($refId, 0, 20) . "</refId>".
669
+ "<subscriptionId>" . $subscriptionId . "</subscriptionId>".
670
+ "<subscription>".
671
+ "<payment>".
672
+ "<creditCard>".
673
+ "<cardNumber>" . $cardNumber . "</cardNumber>".
674
+ "<expirationDate>" . $expirationDate . "</expirationDate>";
675
+ if(!empty($cardCode))
676
+ $this->content .= "<cardCode>" . $cardCode . "</cardCode>";
677
+ $this->content .=
678
+ "</creditCard>".
679
+ "</payment>".
680
+ "<customer>".
681
+ "<email>". substr($customer_email, 0, 255) . "</email>".
682
+ "<phoneNumber>". substr(str_replace("1 (", "(", formatPhone($customer_phone)), 0, 25) . "</phoneNumber>".
683
+ "</customer>".
684
+ "<billTo>".
685
+ "<firstName><![CDATA[". substr($firstName, 0, 50) . "]]></firstName>".
686
+ "<lastName><![CDATA[" . substr($lastName, 0, 50) . "]]></lastName>".
687
+ "<address><![CDATA[". substr($address, 0, 60) . "]]></address>".
688
+ "<city><![CDATA[" . substr($city, 0, 40) . "]]></city>".
689
+ "<state><![CDATA[". substr($state, 0, 2) . "]]></state>".
690
+ "<zip>" . substr($zip, 0, 20) . "</zip>".
691
+ "<country>". substr($country, 0, 60) . "</country>".
692
+ "</billTo>".
693
+ "</subscription>".
694
+ "</ARBUpdateSubscriptionRequest>";
695
+
696
+ //send the xml via curl
697
+ $this->response = $this->send_request_via_curl($host,$path,$this->content);
698
+ //if curl is unavilable you can try using fsockopen
699
+ /*
700
+ $response = send_request_via_fsockopen($host,$path,$order->content);
701
+ */
702
+
703
+
704
+ if(!empty($this->response)) {
705
+ list ($resultCode, $code, $text, $subscriptionId) = $this->parse_return($this->response);
706
+
707
+ if($resultCode == "Ok" || $code == "Ok")
708
+ {
709
+ return true;
710
+ }
711
+ else
712
+ {
713
+ $order->status = "error";
714
+ $order->errorcode = $code;
715
+ $order->error = $text;
716
+ $order->shorterror = $text;
717
+ return false;
718
+ }
719
+ } else {
720
+ $order->status = "error";
721
+ $order->error = "Could not connect to Authorize.net";
722
+ $order->shorterror = "Could not connect to Authorize.net";
723
+ return false;
724
+ }
725
+ }
726
+
727
+ function cancel(&$order)
728
+ {
729
+ //define variables to send
730
+ if(!empty($order->subscription_transaction_id))
731
+ $subscriptionId = $order->subscription_transaction_id;
732
+ else
733
+ $subscriptionId = "";
734
+ $loginname = pmpro_getOption("loginname");
735
+ $transactionkey = pmpro_getOption("transactionkey");
736
+
737
+ if(!empty($order->gateway_environment))
738
+ $gateway_environment = $order->gateway_environment;
739
+ else
740
+ $gateway_environment = pmpro_getOption("gateway_environment");
741
+
742
+ if($gateway_environment == "live")
743
+ $host = "api.authorize.net";
744
+ else
745
+ $host = "apitest.authorize.net";
746
+
747
+ $path = "/xml/v1/request.api";
748
+
749
+ if(!$subscriptionId || !$loginname || !$transactionkey)
750
+ return false;
751
+
752
+ //build xml to post
753
+ $content =
754
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>".
755
+ "<ARBCancelSubscriptionRequest xmlns=\"AnetApi/xml/v1/schema/AnetApiSchema.xsd\">".
756
+ "<merchantAuthentication>".
757
+ "<name>" . $loginname . "</name>".
758
+ "<transactionKey>" . $transactionkey . "</transactionKey>".
759
+ "</merchantAuthentication>" .
760
+ "<subscriptionId>" . $subscriptionId . "</subscriptionId>".
761
+ "</ARBCancelSubscriptionRequest>";
762
+
763
+ //send the xml via curl
764
+ $response = $this->send_request_via_curl($host,$path,$content);
765
+ //if curl is unavilable you can try using fsockopen
766
+ /*
767
+ $response = send_request_via_fsockopen($host,$path,$content);
768
+ */
769
+
770
+ //if the connection and send worked $response holds the return from Authorize.net
771
+ if ($response)
772
+ {
773
+ list ($resultCode, $code, $text, $subscriptionId) = $this->parse_return($response);
774
+
775
+ if($resultCode == "Ok" || $code == "Ok")
776
+ {
777
+ $order->updateStatus("cancelled");
778
+ return true;
779
+ }
780
+ else
781
+ {
782
+ //$order->status = "error";
783
+ $order->errorcode = $code;
784
+ $order->error = $text;
785
+ $order->shorterror = $text;
786
+ return false;
787
+ }
788
+ }
789
+ else
790
+ {
791
+ $order->status = "error";
792
+ $order->error = __("Could not connect to Authorize.net", "pmpro");
793
+ $order->shorterror = __("Could not connect to Authorize.net", "pmpro");
794
+ return false;
795
+ }
796
+ }
797
+
798
+ function getSubscriptionStatus(&$order)
799
+ {
800
+ //define variables to send
801
+ if(!empty($order->subscription_transaction_id))
802
+ $subscriptionId = $order->subscription_transaction_id;
803
+ else
804
+ $subscriptionId = "";
805
+ $loginname = pmpro_getOption("loginname");
806
+ $transactionkey = pmpro_getOption("transactionkey");
807
+
808
+ if(!empty($order->gateway_environment))
809
+ $gateway_environment = $order->gateway_environment;
810
+ else
811
+ $gateway_environment = pmpro_getOption("gateway_environment");
812
+
813
+ if($gateway_environment == "live")
814
+ $host = "api.authorize.net";
815
+ else
816
+ $host = "apitest.authorize.net";
817
+
818
+ $path = "/xml/v1/request.api";
819
+
820
+ if(!$subscriptionId || !$loginname || !$transactionkey)
821
+ return false;
822
+
823
+ //build xml to post
824
+ $content =
825
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>".
826
+ "<ARBGetSubscriptionStatusRequest xmlns=\"AnetApi/xml/v1/schema/AnetApiSchema.xsd\">".
827
+ "<merchantAuthentication>".
828
+ "<name>" . $loginname . "</name>".
829
+ "<transactionKey>" . $transactionkey . "</transactionKey>".
830
+ "</merchantAuthentication>" .
831
+ "<subscriptionId>" . $subscriptionId . "</subscriptionId>".
832
+ "</ARBGetSubscriptionStatusRequest>";
833
+
834
+ //send the xml via curl
835
+ $response = $this->send_request_via_curl($host,$path,$content);
836
+
837
+ //if curl is unavilable you can try using fsockopen
838
+ /*
839
+ $response = send_request_via_fsockopen($host,$path,$content);
840
+ */
841
+
842
+ //if the connection and send worked $response holds the return from Authorize.net
843
+ if($response)
844
+ {
845
+ list ($resultCode, $code, $text, $subscriptionId) = $this->parse_return($response);
846
+
847
+ $status = $this->substring_between($response,'<status>','</status>');
848
+
849
+ if($resultCode == "Ok" || $code == "Ok")
850
+ {
851
+ return $status;
852
+ }
853
+ else
854
+ {
855
+ $order->status = "error";
856
+ $order->errorcode = $resultCode;
857
+ $order->error = $message;
858
+ $order->shorterror = $text;
859
+ }
860
+ }
861
+ else
862
+ {
863
+ $order->status = "error";
864
+ $order->errorcode = $resultCode;
865
+ $order->error = $message;
866
+ $order->shorterror = $text;
867
+ }
868
+ }
869
+
870
+ //Authorize.net Function
871
+ //function to send xml request via fsockopen
872
+ function send_request_via_fsockopen($host,$path,$content)
873
+ {
874
+ $posturl = "ssl://" . $host;
875
+ $header = "Host: $host\r\n";
876
+ $header .= "User-Agent: PHP Script\r\n";
877
+ $header .= "Content-Type: text/xml\r\n";
878
+ $header .= "Content-Length: ".strlen($content)."\r\n";
879
+ $header .= "Connection: close\r\n\r\n";
880
+ $fp = fsockopen($posturl, 443, $errno, $errstr, 30);
881
+ if (!$fp)
882
+ {
883
+ $response = false;
884
+ }
885
+ else
886
+ {
887
+ error_reporting(E_ERROR);
888
+ fputs($fp, "POST $path HTTP/1.1\r\n");
889
+ fputs($fp, $header.$content);
890
+ fwrite($fp, $out);
891
+ $response = "";
892
+ while (!feof($fp))
893
+ {
894
+ $response = $response . fgets($fp, 128);
895
+ }
896
+ fclose($fp);
897
+ error_reporting(E_ALL ^ E_NOTICE);
898
+ }
899
+ return $response;
900
+ }
901
+
902
+ //Authorize.net Function
903
+ //function to send xml request via curl
904
+ function send_request_via_curl($host,$path,$content)
905
+ {
906
+ $posturl = "https://" . $host . $path;
907
+ $posturl = apply_filters("pmpro_authorizenet_post_url", $posturl, pmpro_getOption("gateway_environment"));
908
+ $ch = curl_init();
909
+ curl_setopt($ch, CURLOPT_URL, $posturl);
910
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
911
+ curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type: text/xml"));
912
+ curl_setopt($ch, CURLOPT_HEADER, 1);
913
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $content);
914
+ curl_setopt($ch, CURLOPT_POST, 1);
915
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
916
+ $response = curl_exec($ch);
917
+ return $response;
918
+ }
919
+
920
+
921
+ //Authorize.net Function
922
+ //function to parse Authorize.net response
923
+ function parse_return($content)
924
+ {
925
+ $refId = $this->substring_between($content,'<refId>','</refId>');
926
+ $resultCode = $this->substring_between($content,'<resultCode>','</resultCode>');
927
+ $code = $this->substring_between($content,'<code>','</code>');
928
+ $text = $this->substring_between($content,'<text>','</text>');
929
+ $subscriptionId = $this->substring_between($content,'<subscriptionId>','</subscriptionId>');
930
+ return array ($refId, $resultCode, $code, $text, $subscriptionId);
931
+ }
932
+
933
+ //Authorize.net Function
934
+ //helper function for parsing response
935
+ function substring_between($haystack,$start,$end)
936
+ {
937
+ if (strpos($haystack,$start) === false || strpos($haystack,$end) === false)
938
+ {
939
+ return false;
940
+ }
941
+ else
942
+ {
943
+ $start_position = strpos($haystack,$start)+strlen($start);
944
+ $end_position = strpos($haystack,$end);
945
+ return substr($haystack,$start_position,$end_position-$start_position);
946
+ }
947
+ }
948
+ }
949
+ ?>
classes/gateways/class.pmprogateway_braintree.php ADDED
@@ -0,0 +1,466 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/class.pmprogateway.php");
3
+ if(!class_exists("Braintree"))
4
+ require_once(dirname(__FILE__) . "/../../includes/lib/Braintree/Braintree.php");
5
+ class PMProGateway_braintree
6
+ {
7
+ function PMProGateway_braintree($gateway = NULL)
8
+ {
9
+ $this->gateway = $gateway;
10
+ $this->gateway_environment = pmpro_getOption("gateway_environment");
11
+
12
+ //convert to braintree nomenclature
13
+ $environment = $this->gateway_environment;
14
+ if($environment == "live")
15
+ $environment = "production";
16
+
17
+ Braintree_Configuration::environment($environment);
18
+ Braintree_Configuration::merchantId(pmpro_getOption("braintree_merchantid"));
19
+ Braintree_Configuration::publicKey(pmpro_getOption("braintree_publickey"));
20
+ Braintree_Configuration::privateKey(pmpro_getOption("braintree_privatekey"));
21
+
22
+ return $this->gateway;
23
+ }
24
+
25
+ function process(&$order)
26
+ {
27
+ //check for initial payment
28
+ if(floatval($order->InitialPayment) == 0)
29
+ {
30
+ //just subscribe
31
+ return $this->subscribe($order);
32
+ }
33
+ else
34
+ {
35
+ //charge then subscribe
36
+ if($this->charge($order))
37
+ {
38
+ if(pmpro_isLevelRecurring($order->membership_level))
39
+ {
40
+ if($this->subscribe($order))
41
+ {
42
+ //yay!
43
+ return true;
44
+ }
45
+ else
46
+ {
47
+ //try to refund initial charge
48
+ return false;
49
+ }
50
+ }
51
+ else
52
+ {
53
+ //only a one time charge
54
+ $order->status = "success"; //saved on checkout page
55
+ return true;
56
+ }
57
+ }
58
+ else
59
+ {
60
+ if(empty($order->error))
61
+ $order->error = __("Unknown error: Initial payment failed.", "pmpro");
62
+ return false;
63
+ }
64
+ }
65
+ }
66
+
67
+ function charge(&$order)
68
+ {
69
+ //create a code for the order
70
+ if(empty($order->code))
71
+ $order->code = $order->getRandomCode();
72
+
73
+ //what amount to charge?
74
+ $amount = $order->InitialPayment;
75
+
76
+ //tax
77
+ $order->subtotal = $amount;
78
+ $tax = $order->getTax(true);
79
+ $amount = round((float)$order->subtotal + (float)$tax, 2);
80
+
81
+ //create a customer
82
+ $this->getCustomer($order);
83
+ if(empty($this->customer))
84
+ {
85
+ //failed to create customer
86
+ return false;
87
+ }
88
+
89
+ //charge
90
+ try
91
+ {
92
+ $response = Braintree_Transaction::sale(array(
93
+ 'amount' => $amount,
94
+ 'customerId' => $this->customer->id
95
+ ));
96
+ }
97
+ catch (Exception $e)
98
+ {
99
+ //$order->status = "error";
100
+ $order->errorcode = true;
101
+ $order->error = "Error: " . $e->getMessage();
102
+ $order->shorterror = $order->error;
103
+ return false;
104
+ }
105
+
106
+ if($response->success)
107
+ {
108
+ //successful charge
109
+ $transaction_id = $response->transaction->id;
110
+ $response = Braintree_Transaction::submitForSettlement($transaction_id);
111
+ if($response->success)
112
+ {
113
+ $order->payment_transaction_id = $transaction_id;
114
+ $order->updateStatus("success");
115
+ return true;
116
+ }
117
+ else
118
+ {
119
+ $order->errorcode = true;
120
+ $order->error = __("Error during settlement:", "pmpro") . " " . $response->message;
121
+ $order->shorterror = $response->message;
122
+ return false;
123
+ }
124
+ }
125
+ else
126
+ {
127
+ //$order->status = "error";
128
+ $order->errorcode = true;
129
+ $order->error = __("Error during charge:", "pmpro") . " " . $response->message;
130
+ $order->shorterror = $response->message;
131
+ return false;
132
+ }
133
+ }
134
+
135
+ /*
136
+ This function will return a Braintree customer object.
137
+ If $this->customer is set, it returns it.
138
+ It first checks if the order has a subscription_transaction_id. If so, that's the customer id.
139
+ If not, it checks for a user_id on the order and searches for a customer id in the user meta.
140
+ If a customer id is found, it checks for a customer through the Braintree API.
141
+ If a customer is found and there is an AccountNumber on the order passed, it will update the customer.
142
+ If no customer is found and there is an AccountNumber on the order passed, it will create a customer.
143
+ */
144
+ function getCustomer(&$order, $force = false)
145
+ {
146
+ global $current_user;
147
+
148
+ //already have it?
149
+ if(!empty($this->customer) && !$force)
150
+ return $this->customer;
151
+
152
+ //try based on user id
153
+ if(!empty($order->user_id))
154
+ $user_id = $order->user_id;
155
+
156
+ //if no id passed, check the current user
157
+ if(empty($user_id) && !empty($current_user->ID))
158
+ $user_id = $current_user->ID;
159
+
160
+ //check for a braintree customer id
161
+ if(!empty($user_id))
162
+ {
163
+ $customer_id = get_user_meta($user_id, "pmpro_braintree_customerid", true);
164
+ }
165
+
166
+ //check for an existing stripe customer
167
+ if(!empty($customer_id))
168
+ {
169
+ try
170
+ {
171
+ $this->customer = Braintree_Customer::find($customer_id);
172
+
173
+ //update the customer address, description and card
174
+ if(!empty($order->accountnumber))
175
+ {
176
+ //put data in array for Braintree API calls
177
+ $update_array = array(
178
+ 'firstName' => $order->FirstName,
179
+ 'lastName' => $order->LastName,
180
+ 'creditCard' => array(
181
+ 'number' => $order->braintree->number,
182
+ 'expirationDate' => $order->braintree->expiration_date,
183
+ 'cardholderName' => trim($order->FirstName . " " . $order->LastName),
184
+ 'options' => array(
185
+ 'updateExistingToken' => $this->customer->creditCards[0]->token
186
+ )
187
+ )
188
+ );
189
+
190
+ //address too?
191
+ if(!empty($order->billing))
192
+ //make sure Address2 is set
193
+ if(!isset($order->Address2))
194
+ $order->Address2 = '';
195
+
196
+ //add billing address to array
197
+ $update_array['creditCard']['billingAddress'] = array(
198
+ 'firstName' => $order->FirstName,
199
+ 'lastName' => $order->LastName,
200
+ 'streetAddress' => $order->Address1,
201
+ 'extendedAddress' => $order->Address2,
202
+ 'locality' => $order->billing->city,
203
+ 'region' => $order->billing->state,
204
+ 'postalCode' => $order->billing->zip,
205
+ 'countryCodeAlpha2' => $order->billing->country,
206
+ 'options' => array(
207
+ 'updateExisting' => true
208
+ )
209
+ );
210
+
211
+ //update
212
+ $response = Braintree_Customer::update($customer_id, $update_array);
213
+
214
+ if($response->success)
215
+ {
216
+ $this->customer = $response->customer;
217
+ return $this->customer;
218
+ }
219
+ else
220
+ {
221
+ $order->error = __("Failed to update customer.", "pmpro") . " " . $response->message;
222
+ $order->shorterror = $order->error;
223
+ return false;
224
+ }
225
+ }
226
+
227
+ return $this->customer;
228
+ }
229
+ catch (Exception $e)
230
+ {
231
+ //assume no customer found
232
+ }
233
+ }
234
+
235
+ //no customer id, create one
236
+ if(!empty($order->accountnumber))
237
+ {
238
+ try
239
+ {
240
+ $result = Braintree_Customer::create(array(
241
+ 'firstName' => $order->FirstName,
242
+ 'lastName' => $order->LastName,
243
+ 'email' => $order->Email,
244
+ 'phone' => $order->billing->phone,
245
+ 'creditCard' => array(
246
+ 'number' => $order->braintree->number,
247
+ 'expirationDate' => $order->braintree->expiration_date,
248
+ 'cvv' => $order->braintree->cvv,
249
+ 'cardholderName' => trim($order->FirstName . " " . $order->LastName),
250
+ 'billingAddress' => array(
251
+ 'firstName' => $order->FirstName,
252
+ 'lastName' => $order->LastName,
253
+ 'streetAddress' => $order->Address1,
254
+ 'extendedAddress' => $order->Address2,
255
+ 'locality' => $order->billing->city,
256
+ 'region' => $order->billing->state,
257
+ 'postalCode' => $order->billing->zip,
258
+ 'countryCodeAlpha2' => $order->billing->country
259
+ )
260
+ )
261
+ ));
262
+
263
+ if($result->success)
264
+ {
265
+ $this->customer = $result->customer;
266
+ }
267
+ else
268
+ {
269
+ $order->error = __("Failed to create customer.", "pmpro") . " " . $result->message;
270
+ $order->shorterror = $order->error;
271
+ return false;
272
+ }
273
+ }
274
+ catch (Exception $e)
275
+ {
276
+ $order->error = __("Error creating customer record with Braintree:", "pmpro") . " " . $e->getMessage();
277
+ $order->shorterror = $order->error;
278
+ return false;
279
+ }
280
+
281
+ //if we have no user id, we need to set the customer id after the user is created
282
+ if(empty($user_id))
283
+ {
284
+ global $pmpro_braintree_customerid;
285
+ $pmpro_braintree_customerid = $this->customer->id;
286
+ add_action('user_register', array('PMProGateway_braintree','user_register'));
287
+ }
288
+ else
289
+ update_user_meta($user_id, "pmpro_braintree_customerid", $this->customer->id);
290
+
291
+ return $this->customer;
292
+ }
293
+
294
+ return false;
295
+ }
296
+
297
+ function subscribe(&$order)
298
+ {
299
+ //create a code for the order
300
+ if(empty($order->code))
301
+ $order->code = $order->getRandomCode();
302
+
303
+ //setup customer
304
+ $this->getCustomer($order);
305
+ if(empty($this->customer))
306
+ return false; //error retrieving customer
307
+
308
+ //figure out the amounts
309
+ $amount = $order->PaymentAmount;
310
+ $amount_tax = $order->getTaxForPrice($amount);
311
+ $amount = round((float)$amount + (float)$amount_tax, 2);
312
+
313
+ /*
314
+ There are two parts to the trial. Part 1 is simply the delay until the first payment
315
+ since we are doing the first payment as a separate transaction.
316
+ The second part is the actual "trial" set by the admin.
317
+
318
+ Stripe only supports Year or Month for billing periods, but we account for Days and Weeks just in case.
319
+ */
320
+ //figure out the trial length (first payment handled by initial charge)
321
+ if($order->BillingPeriod == "Year")
322
+ $trial_period_days = $order->BillingFrequency * 365; //annual
323
+ elseif($order->BillingPeriod == "Day")
324
+ $trial_period_days = $order->BillingFrequency * 1; //daily
325
+ elseif($order->BillingPeriod == "Week")
326
+ $trial_period_days = $order->BillingFrequency * 7; //weekly
327
+ else
328
+ $trial_period_days = $order->BillingFrequency * 30; //assume monthly
329
+
330
+ //convert to a profile start date
331
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $trial_period_days . " Day", current_time("timestamp"))) . "T0:0:0";
332
+
333
+ //filter the start date
334
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
335
+
336
+ //convert back to days
337
+ $trial_period_days = ceil(abs(strtotime(date("Y-m-d")) - strtotime($order->ProfileStartDate, current_time("timestamp"))) / 86400);
338
+
339
+ //now add the actual trial set by the site
340
+ if(!empty($order->TrialBillingCycles))
341
+ {
342
+ $trialOccurrences = (int)$order->TrialBillingCycles;
343
+ if($order->BillingPeriod == "Year")
344
+ $trial_period_days = $trial_period_days + (365 * $order->BillingFrequency * $trialOccurrences); //annual
345
+ elseif($order->BillingPeriod == "Day")
346
+ $trial_period_days = $trial_period_days + (1 * $order->BillingFrequency * $trialOccurrences); //daily
347
+ elseif($order->BillingPeriod == "Week")
348
+ $trial_period_days = $trial_period_days + (7 * $order->BillingFrequency * $trialOccurrences); //weekly
349
+ else
350
+ $trial_period_days = $trial_period_days + (30 * $order->BillingFrequency * $trialOccurrences); //assume monthly
351
+ }
352
+
353
+ //subscribe to the plan
354
+ try
355
+ {
356
+ $details = array(
357
+ 'paymentMethodToken' => $this->customer->creditCards[0]->token,
358
+ 'planId' => 'pmpro_' . $order->membership_id,
359
+ 'price' => $amount
360
+ );
361
+
362
+ if(!empty($trial_period_days))
363
+ {
364
+ $details['trialPeriod'] = true;
365
+ $details['trialDuration'] = $trial_period_days;
366
+ $details['trialDurationUnit'] = "day";
367
+ }
368
+
369
+ if(!empty($order->TotalBillingCycles))
370
+ $details['numberOfBillingCycles'] = $order->TotalBillingCycles;
371
+
372
+ $result = Braintree_Subscription::create($details);
373
+ }
374
+ catch (Exception $e)
375
+ {
376
+ $order->error = __("Error subscribing customer to plan with Braintree:", "pmpro") . " " . $e->getMessage();
377
+ //return error
378
+ $order->shorterror = $order->error;
379
+ return false;
380
+ }
381
+
382
+ if($result->success)
383
+ {
384
+ //if we got this far, we're all good
385
+ $order->status = "success";
386
+ $order->subscription_transaction_id = $result->subscription->id;
387
+ return true;
388
+ }
389
+ else
390
+ {
391
+ $order->error = __("Failed to subscribe with Braintree:", "pmpro") . " " . $result->message;
392
+ $order->shorterror = $result->message;
393
+ return false;
394
+ }
395
+ }
396
+
397
+ function update(&$order)
398
+ {
399
+ //we just have to run getCustomer which will look for the customer and update it with the new token
400
+ $this->getCustomer($order, true);
401
+
402
+ if(!empty($this->customer) && empty($order->error))
403
+ {
404
+ return true;
405
+ }
406
+ else
407
+ {
408
+ return false; //couldn't find the customer
409
+ }
410
+ }
411
+
412
+ function cancel(&$order)
413
+ {
414
+ //require a subscription id
415
+ if(empty($order->subscription_transaction_id))
416
+ return false;
417
+
418
+ //find the customer
419
+ if(!empty($order->subscription_transaction_id))
420
+ {
421
+ //cancel
422
+ try
423
+ {
424
+ $result = Braintree_Subscription::cancel($order->subscription_transaction_id);
425
+ }
426
+ catch(Exception $e)
427
+ {
428
+ $order->updateStatus("cancelled"); //assume it's been cancelled already
429
+ $order->error = __("Could not find the subscription.", "pmpro") . " " . $e->getMessage();
430
+ $order->shorterror = $order->error;
431
+ return false; //no subscription found
432
+ }
433
+
434
+ if($result->success)
435
+ {
436
+ $order->updateStatus("cancelled");
437
+ return true;
438
+ }
439
+ else
440
+ {
441
+ $order->updateStatus("cancelled"); //assume it's been cancelled already
442
+ $order->error = __("Could not find the subscription.", "pmpro") . " " . $result->message;
443
+ $order->shorterror = $order->error;
444
+ return false; //no subscription found
445
+ }
446
+ }
447
+ else
448
+ {
449
+ $order->error = __("Could not find the subscription.", "pmpro");
450
+ $order->shorterror = $order->error;
451
+ return false; //no customer found
452
+ }
453
+ }
454
+
455
+ /*
456
+ Save Braintree customer id after the user is registered.
457
+ */
458
+ static function user_register($user_id)
459
+ {
460
+ global $pmpro_braintree_customerid;
461
+ if(!empty($pmpro_braintree_customerid))
462
+ {
463
+ update_user_meta($user_id, 'pmpro_braintree_customerid', $pmpro_braintree_customerid);
464
+ }
465
+ }
466
+ }
classes/gateways/class.pmprogateway_check.php ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/class.pmprogateway.php");
3
+ class PMProGateway_check
4
+ {
5
+ function PMProGateway_check($gateway = NULL)
6
+ {
7
+ $this->gateway = $gateway;
8
+ return $this->gateway;
9
+ }
10
+
11
+ function process(&$order)
12
+ {
13
+ //clean up a couple values
14
+ $order->payment_type = "Check";
15
+ $order->CardType = "";
16
+ $order->cardtype = "";
17
+
18
+ //check for initial payment
19
+ if(floatval($order->InitialPayment) == 0)
20
+ {
21
+ //auth first, then process
22
+ if($this->authorize($order))
23
+ {
24
+ $this->void($order);
25
+ if(!pmpro_isLevelTrial($order->membership_level))
26
+ {
27
+ //subscription will start today with a 1 period trial
28
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
29
+ $order->TrialBillingPeriod = $order->BillingPeriod;
30
+ $order->TrialBillingFrequency = $order->BillingFrequency;
31
+ $order->TrialBillingCycles = 1;
32
+ $order->TrialAmount = 0;
33
+
34
+ //add a billing cycle to make up for the trial, if applicable
35
+ if(!empty($order->TotalBillingCycles))
36
+ $order->TotalBillingCycles++;
37
+ }
38
+ elseif($order->InitialPayment == 0 && $order->TrialAmount == 0)
39
+ {
40
+ //it has a trial, but the amount is the same as the initial payment, so we can squeeze it in there
41
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
42
+ $order->TrialBillingCycles++;
43
+
44
+ //add a billing cycle to make up for the trial, if applicable
45
+ if($order->TotalBillingCycles)
46
+ $order->TotalBillingCycles++;
47
+ }
48
+ else
49
+ {
50
+ //add a period to the start date to account for the initial payment
51
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $order->BillingFrequency . " " . $order->BillingPeriod, current_time("timestamp"))) . "T0:0:0";
52
+ }
53
+
54
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
55
+ return $this->subscribe($order);
56
+ }
57
+ else
58
+ {
59
+ if(empty($order->error))
60
+ $order->error = __("Unknown error: Authorization failed.", "pmpro");
61
+ return false;
62
+ }
63
+ }
64
+ else
65
+ {
66
+ //charge first payment
67
+ if($this->charge($order))
68
+ {
69
+ //setup recurring billing
70
+ if(pmpro_isLevelRecurring($order->membership_level))
71
+ {
72
+ if(!pmpro_isLevelTrial($order->membership_level))
73
+ {
74
+ //subscription will start today with a 1 period trial
75
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
76
+ $order->TrialBillingPeriod = $order->BillingPeriod;
77
+ $order->TrialBillingFrequency = $order->BillingFrequency;
78
+ $order->TrialBillingCycles = 1;
79
+ $order->TrialAmount = 0;
80
+
81
+ //add a billing cycle to make up for the trial, if applicable
82
+ if(!empty($order->TotalBillingCycles))
83
+ $order->TotalBillingCycles++;
84
+ }
85
+ elseif($order->InitialPayment == 0 && $order->TrialAmount == 0)
86
+ {
87
+ //it has a trial, but the amount is the same as the initial payment, so we can squeeze it in there
88
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
89
+ $order->TrialBillingCycles++;
90
+
91
+ //add a billing cycle to make up for the trial, if applicable
92
+ if(!empty($order->TotalBillingCycles))
93
+ $order->TotalBillingCycles++;
94
+ }
95
+ else
96
+ {
97
+ //add a period to the start date to account for the initial payment
98
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $this->BillingFrequency . " " . $this->BillingPeriod, current_time("timestamp"))) . "T0:0:0";
99
+ }
100
+
101
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
102
+ if($this->subscribe($order))
103
+ {
104
+ return true;
105
+ }
106
+ else
107
+ {
108
+ if($this->void($order))
109
+ {
110
+ if(!$order->error)
111
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
112
+ }
113
+ else
114
+ {
115
+ if(!$order->error)
116
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
117
+
118
+ $order->error .= " " . __("A partial payment was made that we could not void. Please contact the site owner immediately to correct this.", "pmpro");
119
+ }
120
+
121
+ return false;
122
+ }
123
+ }
124
+ else
125
+ {
126
+ //only a one time charge
127
+ $order->status = apply_filters("pmpro_check_status_after_checkout", "success"); //saved on checkout page
128
+ return true;
129
+ }
130
+ }
131
+ else
132
+ {
133
+ if(empty($order->error))
134
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
135
+
136
+ return false;
137
+ }
138
+ }
139
+ }
140
+
141
+ function authorize(&$order)
142
+ {
143
+ //create a code for the order
144
+ if(empty($order->code))
145
+ $order->code = $order->getRandomCode();
146
+
147
+ //simulate a successful authorization
148
+ $order->payment_transaction_id = "CHECK" . $order->code;
149
+ $order->updateStatus("authorized");
150
+ return true;
151
+ }
152
+
153
+ function void(&$order)
154
+ {
155
+ //need a transaction id
156
+ if(empty($order->payment_transaction_id))
157
+ return false;
158
+
159
+ //simulate a successful void
160
+ $order->payment_transaction_id = "CHECK" . $order->code;
161
+ $order->updateStatus("voided");
162
+ return true;
163
+ }
164
+
165
+ function charge(&$order)
166
+ {
167
+ //create a code for the order
168
+ if(empty($order->code))
169
+ $order->code = $order->getRandomCode();
170
+
171
+ //simulate a successful charge
172
+ $order->payment_transaction_id = "CHECK" . $order->code;
173
+ $order->updateStatus("success");
174
+ return true;
175
+ }
176
+
177
+ function subscribe(&$order)
178
+ {
179
+ //create a code for the order
180
+ if(empty($order->code))
181
+ $order->code = $order->getRandomCode();
182
+
183
+ //filter order before subscription. use with care.
184
+ $order = apply_filters("pmpro_subscribe_order", $order, $this);
185
+
186
+ //simulate a successful subscription processing
187
+ $order->status = "success";
188
+ $order->subscription_transaction_id = "CHECK" . $order->code;
189
+ return true;
190
+ }
191
+
192
+ function update(&$order)
193
+ {
194
+ //simulate a successful billing update
195
+ return true;
196
+ }
197
+
198
+ function cancel(&$order)
199
+ {
200
+ //require a subscription id
201
+ if(empty($order->subscription_transaction_id))
202
+ return false;
203
+
204
+ //simulate a successful cancel
205
+ $order->updateStatus("cancelled");
206
+ return true;
207
+ }
208
+ }
classes/gateways/class.pmprogateway_cybersource.php ADDED
@@ -0,0 +1,764 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/class.pmprogateway.php");
3
+ if(!class_exists("CyberSourceSoapClient"))
4
+ require_once(dirname(__FILE__) . "/../../includes/lib/CyberSource/cyber_source_soap_client.php");
5
+ class PMProGateway_cybersource
6
+ {
7
+ function PMProGateway_cybersource($gateway = NULL)
8
+ {
9
+ $this->gateway = $gateway;
10
+ return $this->gateway;
11
+ }
12
+
13
+ function process(&$order)
14
+ {
15
+ //check for initial payment
16
+ if(floatval($order->InitialPayment) == 0)
17
+ {
18
+ //auth first, then process
19
+ if($this->authorize($order))
20
+ {
21
+ $this->void($order);
22
+ if(!pmpro_isLevelTrial($order->membership_level))
23
+ {
24
+ //subscription will start today with a 1 period trial
25
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
26
+ $order->TrialBillingPeriod = $order->BillingPeriod;
27
+ $order->TrialBillingFrequency = $order->BillingFrequency;
28
+ $order->TrialBillingCycles = 1;
29
+ $order->TrialAmount = 0;
30
+
31
+ //add a billing cycle to make up for the trial, if applicable
32
+ if(!empty($order->TotalBillingCycles))
33
+ $order->TotalBillingCycles++;
34
+ }
35
+ elseif($order->InitialPayment == 0 && $order->TrialAmount == 0)
36
+ {
37
+ //it has a trial, but the amount is the same as the initial payment, so we can squeeze it in there
38
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
39
+ $order->TrialBillingCycles++;
40
+
41
+ //add a billing cycle to make up for the trial, if applicable
42
+ if($order->TotalBillingCycles)
43
+ $order->TotalBillingCycles++;
44
+ }
45
+ else
46
+ {
47
+ //add a period to the start date to account for the initial payment
48
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $order->BillingFrequency . " " . $order->BillingPeriod, current_time("timestamp"))) . "T0:0:0";
49
+ }
50
+
51
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
52
+ return $this->subscribe($order);
53
+ }
54
+ else
55
+ {
56
+ if(empty($order->error))
57
+ $order->error = __("Unknown error: Authorization failed.", "pmpro");
58
+ return false;
59
+ }
60
+ }
61
+ else
62
+ {
63
+ //charge first payment
64
+ if($this->charge($order))
65
+ {
66
+ //setup recurring billing
67
+ if(pmpro_isLevelRecurring($order->membership_level))
68
+ {
69
+ if(!pmpro_isLevelTrial($order->membership_level))
70
+ {
71
+ //subscription will start today with a 1 period trial
72
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
73
+ $order->TrialBillingPeriod = $order->BillingPeriod;
74
+ $order->TrialBillingFrequency = $order->BillingFrequency;
75
+ $order->TrialBillingCycles = 1;
76
+ $order->TrialAmount = 0;
77
+
78
+ //add a billing cycle to make up for the trial, if applicable
79
+ if(!empty($order->TotalBillingCycles))
80
+ $order->TotalBillingCycles++;
81
+ }
82
+ elseif($order->InitialPayment == 0 && $order->TrialAmount == 0)
83
+ {
84
+ //it has a trial, but the amount is the same as the initial payment, so we can squeeze it in there
85
+ $order->ProfileStartDate = date("Y-m-d") . "T0:0:0";
86
+ $order->TrialBillingCycles++;
87
+
88
+ //add a billing cycle to make up for the trial, if applicable
89
+ if(!empty($order->TotalBillingCycles))
90
+ $order->TotalBillingCycles++;
91
+ }
92
+ else
93
+ {
94
+ //add a period to the start date to account for the initial payment
95
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $this->BillingFrequency . " " . $this->BillingPeriod, current_time("timestamp"))) . "T0:0:0";
96
+ }
97
+
98
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
99
+ if($this->subscribe($order))
100
+ {
101
+ return true;
102
+ }
103
+ else
104
+ {
105
+ if($this->void($order))
106
+ {
107
+ if(!$order->error)
108
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
109
+ }
110
+ else
111
+ {
112
+ if(!$order->error)
113
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
114
+
115
+ $order->error .= " " . __("A partial payment was made that we could not void. Please contact the site owner immediately to correct this.", "pmpro");
116
+ }
117
+
118
+ return false;
119
+ }
120
+ }
121
+ else
122
+ {
123
+ //only a one time charge
124
+ $order->status = "success"; //saved on checkout page
125
+ return true;
126
+ }
127
+ }
128
+ else
129
+ {
130
+ if(empty($order->error))
131
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
132
+
133
+ return false;
134
+ }
135
+ }
136
+ }
137
+
138
+ function getCardType($name)
139
+ {
140
+ $card_types = array(
141
+ 'Visa' => '001',
142
+ 'MasterCard' => '002',
143
+ 'Master Card' => '002',
144
+ 'AMEX' => '003',
145
+ 'American Express' => '003',
146
+ 'Discover' => '004',
147
+ 'Diners Club' => '005',
148
+ 'Carte Blanche' => '006',
149
+ 'JCB' => '007'
150
+ );
151
+
152
+ if(isset($card_types[$name]))
153
+ return $card_types[$name];
154
+ else
155
+ return false;
156
+ }
157
+
158
+ function getWSDL($order)
159
+ {
160
+ //which gateway environment?
161
+ if(empty($order->gateway_environment))
162
+ $gateway_environment = pmpro_getOption("gateway_environment");
163
+ else
164
+ $gateway_environment = $order->gateway_environment;
165
+
166
+ //which host?
167
+ if($gateway_environment == "live")
168
+ $host = "ics2ws.ic3.com";
169
+ else
170
+ $host = "ics2wstest.ic3.com";
171
+
172
+ //path
173
+ $path = "/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.90.wsdl";
174
+
175
+ //build url
176
+ $wsdl_url = "https://" . $host . $path;
177
+
178
+ //filter
179
+ $wsdl_url = apply_filters("pmpro_cybersource_wsdl_url", $wsdl_url, $gateway_environment);
180
+
181
+ return $wsdl_url;
182
+ }
183
+
184
+ function authorize(&$order)
185
+ {
186
+ if(empty($order->code))
187
+ $order->code = $order->getRandomCode();
188
+
189
+ $wsdl_url = $this->getWSDL($order);
190
+
191
+ //what amount to authorize? just $1 to test
192
+ $amount = "1.00";
193
+
194
+ //combine address
195
+ $address = $order->Address1;
196
+ if(!empty($order->Address2))
197
+ $address .= "\n" . $order->Address2;
198
+
199
+ //customer stuff
200
+ $customer_email = $order->Email;
201
+ $customer_phone = $order->billing->phone;
202
+
203
+ if(!isset($order->membership_level->name))
204
+ $order->membership_level->name = "";
205
+
206
+ //to store our request
207
+ $request = new stdClass();
208
+
209
+ //which service?
210
+ $ccAuthService = new stdClass();
211
+ $ccAuthService->run = "true";
212
+ $request->ccAuthService = $ccAuthService;
213
+
214
+ //merchant id and order code
215
+ $request->merchantID = pmpro_getOption("cybersource_merchantid");
216
+ $request->merchantReferenceCode = $order->code;
217
+
218
+ //bill to
219
+ $billTo = new stdClass();
220
+ $billTo->firstName = $order->FirstName;
221
+ $billTo->lastName = $order->LastName;
222
+ $billTo->street1 = $address;
223
+ $billTo->city = $order->billing->city;
224
+ $billTo->state = $order->billing->state;
225
+ $billTo->postalCode = $order->billing->zip;
226
+ $billTo->country = $order->billing->country;
227
+ $billTo->email = $order->Email;
228
+ $billTo->ipAddress = $_SERVER['REMOTE_ADDR'];
229
+ $request->billTo = $billTo;
230
+
231
+ //card
232
+ $card = new stdClass();
233
+ $card->cardType = $this->getCardType($order->cardtype);
234
+ $card->accountNumber = $order->accountnumber;
235
+ $card->expirationMonth = $order->expirationmonth;
236
+ $card->expirationYear = $order->expirationyear;
237
+ $card->cvNumber = $order->CVV2;
238
+ $request->card = $card;
239
+
240
+ //currency
241
+ $purchaseTotals = new stdClass();
242
+ $purchaseTotals->currency = pmpro_getOption("currency");
243
+ $request->purchaseTotals = $purchaseTotals;
244
+
245
+ //item/price
246
+ $item0 = new stdClass();
247
+ $item0->unitPrice = $amount;
248
+ $item0->quantity = "1";
249
+ $item0->productName = $order->membership_level->name . " Membership";
250
+ $item0->productSKU = $order->membership_level->id;
251
+ $item0->id = $order->membership_id;
252
+ $request->item = array($item0);
253
+
254
+ $soapClient = new CyberSourceSoapClient($wsdl_url, array("merchantID"=>pmpro_getOption("cybersource_merchantid"), "transactionKey"=>pmpro_getOption("cybersource_securitykey")));
255
+ $reply = $soapClient->runTransaction($request);
256
+
257
+ if($reply->reasonCode == "100")
258
+ {
259
+ //success
260
+ $order->payment_transaction_id = $reply->requestID;
261
+ $order->updateStatus("authorized");
262
+ return true;
263
+ }
264
+ else
265
+ {
266
+ //error
267
+ $order->errorcode = $reply->reasonCode;
268
+ $order->error = $this->getErrorFromCode($reply->reasonCode);
269
+ $order->shorterror = $this->getErrorFromCode($reply->reasonCode);
270
+ return false;
271
+ }
272
+ }
273
+
274
+ function void(&$order)
275
+ {
276
+ //need a transaction id
277
+ if(empty($order->payment_transaction_id))
278
+ return false;
279
+
280
+ //get wsdl
281
+ $wsdl_url = $this->getWSDL($order);
282
+
283
+ //to store our request
284
+ $request = new stdClass();
285
+
286
+ //which service?
287
+ $voidService = new stdClass();
288
+ $voidService->run = "true";
289
+ $voidService->voidRequestID = $order->payment_transaction_id;
290
+ $request->voidService = $voidService;
291
+
292
+ //merchant id and order code
293
+ $request->merchantID = pmpro_getOption("cybersource_merchantid");
294
+ $request->merchantReferenceCode = $order->code;
295
+
296
+ $soapClient = new CyberSourceSoapClient($wsdl_url, array("merchantID"=>pmpro_getOption("cybersource_merchantid"), "transactionKey"=>pmpro_getOption("cybersource_securitykey")));
297
+ $reply = $soapClient->runTransaction($request);
298
+
299
+ if($reply->reasonCode == "100")
300
+ {
301
+ //success
302
+ $order->payment_transaction_id = $reply->requestID;
303
+ $order->updateStatus("voided");
304
+ return true;
305
+ }
306
+ else
307
+ {
308
+ //error
309
+ $order->errorcode = $reply->reasonCode;
310
+ $order->error = $this->getErrorFromCode($reply->reasonCode);
311
+ $order->shorterror = $this->getErrorFromCode($reply->reasonCode);
312
+ return false;
313
+ }
314
+ }
315
+
316
+ function charge(&$order)
317
+ {
318
+ //get a code
319
+ if(empty($order->code))
320
+ $order->code = $order->getRandomCode();
321
+
322
+ //get wsdl
323
+ $wsdl_url = $this->getWSDL($order);
324
+
325
+ //what amount to charge?
326
+ $amount = $order->InitialPayment;
327
+
328
+ //tax
329
+ $order->subtotal = $amount;
330
+ $tax = $order->getTax(true);
331
+ $amount = round((float)$order->subtotal + (float)$tax, 2);
332
+
333
+ //combine address
334
+ $address = $order->Address1;
335
+ if(!empty($order->Address2))
336
+ $address .= "\n" . $order->Address2;
337
+
338
+ //customer stuff
339
+ $customer_email = $order->Email;
340
+ $customer_phone = $order->billing->phone;
341
+
342
+ if(!isset($order->membership_level->name))
343
+ $order->membership_level->name = "";
344
+
345
+ //to store our request
346
+ $request = new stdClass();
347
+
348
+ //authorize and capture
349
+ $ccAuthService = new stdClass();
350
+ $ccAuthService->run = "true";
351
+ $request->ccAuthService = $ccAuthService;
352
+
353
+ $ccCaptureService = new stdClass();
354
+ $ccCaptureService->run = "true";
355
+ $request->ccCaptureService = $ccCaptureService;
356
+
357
+ //merchant id and order code
358
+ $request->merchantID = pmpro_getOption("cybersource_merchantid");
359
+ $request->merchantReferenceCode = $order->code;
360
+
361
+ //bill to
362
+ $billTo = new stdClass();
363
+ $billTo->firstName = $order->FirstName;
364
+ $billTo->lastName = $order->LastName;
365
+ $billTo->street1 = $address;
366
+ $billTo->city = $order->billing->city;
367
+ $billTo->state = $order->billing->state;
368
+ $billTo->postalCode = $order->billing->zip;
369
+ $billTo->country = $order->billing->country;
370
+ $billTo->email = $order->Email;
371
+ $billTo->ipAddress = $_SERVER['REMOTE_ADDR'];
372
+ $request->billTo = $billTo;
373
+
374
+ //card
375
+ $card = new stdClass();
376
+ $card->cardType = $this->getCardType($order->cardtype);
377
+ $card->accountNumber = $order->accountnumber;
378
+ $card->expirationMonth = $order->expirationmonth;
379
+ $card->expirationYear = $order->expirationyear;
380
+ $card->cvNumber = $order->CVV2;
381
+ $request->card = $card;
382
+
383
+ //currency
384
+ $purchaseTotals = new stdClass();
385
+ $purchaseTotals->currency = pmpro_getOption("currency");
386
+ $request->purchaseTotals = $purchaseTotals;
387
+
388
+ //item/price
389
+ $item0 = new stdClass();
390
+ $item0->unitPrice = $amount;
391
+ $item0->quantity = "1";
392
+ $item0->productName = $order->membership_level->name . " Membership";
393
+ $item0->productSKU = $order->membership_level->id;
394
+ $item0->id = $order->membership_id;
395
+ $request->item = array($item0);
396
+
397
+ $soapClient = new CyberSourceSoapClient($wsdl_url, array("merchantID"=>pmpro_getOption("cybersource_merchantid"), "transactionKey"=>pmpro_getOption("cybersource_securitykey")));
398
+ $reply = $soapClient->runTransaction($request);
399
+
400
+ if($reply->reasonCode == "100")
401
+ {
402
+ //success
403
+ $order->payment_transaction_id = $reply->requestID;
404
+ $order->updateStatus("success");
405
+ return true;
406
+ }
407
+ else
408
+ {
409
+ //error
410
+ $order->errorcode = $reply->reasonCode;
411
+ $order->error = $this->getErrorFromCode($reply->reasonCode);
412
+ $order->shorterror = $this->getErrorFromCode($reply->reasonCode);
413
+ return false;
414
+ }
415
+ }
416
+
417
+ function subscribe(&$order)
418
+ {
419
+ //create a code for the order
420
+ if(empty($order->code))
421
+ $order->code = $order->getRandomCode();
422
+
423
+ //filter order before subscription. use with care.
424
+ $order = apply_filters("pmpro_subscribe_order", $order, $this);
425
+
426
+ //get wsdl
427
+ $wsdl_url = $this->getWSDL($order);
428
+
429
+ //to store our request
430
+ $request = new stdClass();
431
+
432
+ //set service type
433
+ $paySubscriptionCreateService = new stdClass();
434
+ $paySubscriptionCreateService->run = 'true';
435
+ $paySubscriptionCreateService->disableAutoAuth = 'true'; //we do our own auth check
436
+ $request->paySubscriptionCreateService = $paySubscriptionCreateService;
437
+
438
+ //merchant id and order code
439
+ $request->merchantID = pmpro_getOption("cybersource_merchantid");
440
+ $request->merchantReferenceCode = $order->code;
441
+
442
+ /*
443
+ setup billing amount/etc
444
+ */
445
+ //figure out the amounts
446
+ $amount = $order->PaymentAmount;
447
+ $amount_tax = $order->getTaxForPrice($amount);
448
+ $amount = round((float)$amount + (float)$amount_tax, 2);
449
+
450
+ /*
451
+ There are two parts to the trial. Part 1 is simply the delay until the first payment
452
+ since we are doing the first payment as a separate transaction.
453
+ The second part is the actual "trial" set by the admin.
454
+ */
455
+ //figure out the trial length (first payment handled by initial charge)
456
+ if($order->BillingPeriod == "Year")
457
+ $trial_period_days = $order->BillingFrequency * 365; //annual
458
+ elseif($order->BillingPeriod == "Day")
459
+ $trial_period_days = $order->BillingFrequency * 1; //daily
460
+ elseif($order->BillingPeriod == "Week")
461
+ $trial_period_days = $order->BillingFrequency * 7; //weekly
462
+ else
463
+ $trial_period_days = $order->BillingFrequency * 30; //assume monthly
464
+
465
+ //convert to a profile start date
466
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $trial_period_days . " Day", current_time("timestamp"))) . "T0:0:0";
467
+
468
+ //filter the start date
469
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
470
+
471
+ //convert back to days
472
+ $trial_period_days = ceil(abs(strtotime(date("Y-m-d"), current_time('timestamp')) - strtotime($order->ProfileStartDate, current_time("timestamp"))) / 86400);
473
+
474
+ //now add the actual trial set by the site
475
+ if(!empty($order->TrialBillingCycles))
476
+ {
477
+ $trialOccurrences = (int)$order->TrialBillingCycles;
478
+ if($order->BillingPeriod == "Year")
479
+ $trial_period_days = $trial_period_days + (365 * $order->BillingFrequency * $trialOccurrences); //annual
480
+ elseif($order->BillingPeriod == "Day")
481
+ $trial_period_days = $trial_period_days + (1 * $order->BillingFrequency * $trialOccurrences); //daily
482
+ elseif($order->BillingPeriod == "Week")
483
+ $trial_period_days = $trial_period_days + (7 * $order->BillingFrequency * $trialOccurrences); //weekly
484
+ else
485
+ $trial_period_days = $trial_period_days + (30 * $order->BillingFrequency * $trialOccurrences); //assume monthly
486
+ }
487
+
488
+ //convert back into a date
489
+ $profile_start_date = date("Ymd", strtotime("+ " . $trial_period_days . " Days"));
490
+
491
+ //figure out the frequency
492
+ if($order->BillingPeriod == "Year")
493
+ {
494
+ $frequency = "annually"; //ignoring BillingFrequency set on level.
495
+ }
496
+ elseif($order->BillingPeriod == "Month")
497
+ {
498
+ if($order->BillingFrequency == 6)
499
+ $frequency = "semi annually";
500
+ elseif($order->BillingFrequency == 3)
501
+ $frequency = "quarterly";
502
+ else
503
+ $frequency = "monthly";
504
+ }
505
+ elseif($order->BillingPeriod == "Week")
506
+ {
507
+ if($order->BillingFrequency == 4)
508
+ $frequency = "quad-weekly";
509
+ elseif($order->BillingFrequency == 2)
510
+ $frequency = "bi-weekly";
511
+ else
512
+ $frequency = "weekly";
513
+ }
514
+ elseif($order->BillingPeriod == "Day")
515
+ {
516
+ if($order->BillingFrequency == 365)
517
+ $frequency = "annually";
518
+ elseif($order->BillingFrequency == 182)
519
+ $frequency = "semi annually";
520
+ elseif($order->BillingFrequency == 183)
521
+ $frequency = "semi annually";
522
+ elseif($order->BillingFrequency == 90)
523
+ $frequency = "quaterly";
524
+ elseif($order->BillingFrequency == 30)
525
+ $frequency = "monthly";
526
+ elseif($order->BillingFrequency == 15)
527
+ $frequency = "semi-monthly";
528
+ elseif($order->BillingFrequency == 28)
529
+ $frequency = "quad-weekly";
530
+ elseif($order->BillingFrequency == 14)
531
+ $frequency = "bi-weekly";
532
+ elseif($order->BillingFrequency == 7)
533
+ $frequency = "weekly";
534
+ }
535
+
536
+ //set subscription info for API
537
+ $subscription = new stdClass();
538
+ $subscription->title = $order->membership_level->name;
539
+ $subscription->paymentMethod = "credit card";
540
+ $request->subscription = $subscription;
541
+
542
+ //recurring info
543
+ $recurringSubscriptionInfo = new stdClass();
544
+ $recurringSubscriptionInfo->amount = number_format($amount, 2);
545
+ $recurringSubscriptionInfo->startDate = $profile_start_date;
546
+ $recurringSubscriptionInfo->frequency = $frequency;
547
+ if(!empty($order->TotalBillingCycles))
548
+ $recurringSubscriptionInfo->numberOfPayments = $order->TotalBillingCycles;
549
+ $request->recurringSubscriptionInfo = $recurringSubscriptionInfo;
550
+
551
+ //combine address
552
+ $address = $order->Address1;
553
+ if(!empty($order->Address2))
554
+ $address .= "\n" . $order->Address2;
555
+
556
+ //bill to
557
+ $billTo = new stdClass();
558
+ $billTo->firstName = $order->FirstName;
559
+ $billTo->lastName = $order->LastName;
560
+ $billTo->street1 = $address;
561
+ $billTo->city = $order->billing->city;
562
+ $billTo->state = $order->billing->state;
563
+ $billTo->postalCode = $order->billing->zip;
564
+ $billTo->country = $order->billing->country;
565
+ $billTo->email = $order->Email;
566
+ $billTo->ipAddress = $_SERVER['REMOTE_ADDR'];
567
+ $request->billTo = $billTo;
568
+
569
+ //card
570
+ $card = new stdClass();
571
+ $card->cardType = $this->getCardType($order->cardtype);
572
+ $card->accountNumber = $order->accountnumber;
573
+ $card->expirationMonth = $order->expirationmonth;
574
+ $card->expirationYear = $order->expirationyear;
575
+ $card->cvNumber = $order->CVV2;
576
+ $request->card = $card;
577
+
578
+ //currency
579
+ $purchaseTotals = new stdClass();
580
+ $purchaseTotals->currency = pmpro_getOption("currency");
581
+ $request->purchaseTotals = $purchaseTotals;
582
+
583
+ $soapClient = new CyberSourceSoapClient($wsdl_url, array("merchantID"=>pmpro_getOption("cybersource_merchantid"), "transactionKey"=>pmpro_getOption("cybersource_securitykey")));
584
+ $reply = $soapClient->runTransaction($request);
585
+
586
+ if($reply->reasonCode == "100")
587
+ {
588
+ //success
589
+ $order->subscription_transaction_id = $reply->requestID;
590
+ $order->status = "success";
591
+ return true;
592
+ }
593
+ else
594
+ {
595
+ //error
596
+ $order->status = "error";
597
+ $order->errorcode = $reply->reasonCode;
598
+ $order->error = $this->getErrorFromCode($reply->reasonCode);
599
+ $order->shorterror = $this->getErrorFromCode($reply->reasonCode);
600
+ return false;
601
+ }
602
+ }
603
+
604
+ function update(&$order)
605
+ {
606
+ //get wsdl
607
+ $wsdl_url = $this->getWSDL($order);
608
+
609
+ //to store our request
610
+ $request = new stdClass();
611
+
612
+ //set service type
613
+ $paySubscriptionUpdateService = new stdClass();
614
+ $paySubscriptionUpdateService ->run = "true";
615
+ $request->paySubscriptionUpdateService = $paySubscriptionUpdateService ;
616
+
617
+ //merchant id and order code
618
+ $request->merchantID = pmpro_getOption("cybersource_merchantid");
619
+ $request->merchantReferenceCode = $order->code;
620
+
621
+ //set subscription info for API
622
+ $recurringSubscriptionInfo = new stdClass();
623
+ $recurringSubscriptionInfo->subscriptionID = $order->subscription_transaction_id;
624
+ $request->recurringSubscriptionInfo = $recurringSubscriptionInfo;
625
+
626
+ //combine address
627
+ $address = $order->Address1;
628
+ if(!empty($order->Address2))
629
+ $address .= "\n" . $order->Address2;
630
+
631
+ //bill to
632
+ $billTo = new stdClass();
633
+ $billTo->firstName = $order->FirstName;
634
+ $billTo->lastName = $order->LastName;
635
+ $billTo->street1 = $address;
636
+ $billTo->city = $order->billing->city;
637
+ $billTo->state = $order->billing->state;
638
+ $billTo->postalCode = $order->billing->zip;
639
+ $billTo->country = $order->billing->country;
640
+ $billTo->email = $order->Email;
641
+ $billTo->ipAddress = $_SERVER['REMOTE_ADDR'];
642
+ $request->billTo = $billTo;
643
+
644
+ //card
645
+ $card = new stdClass();
646
+ $card->cardType = $this->getCardType($order->cardtype);
647
+ $card->accountNumber = $order->accountnumber;
648
+ $card->expirationMonth = $order->expirationmonth;
649
+ $card->expirationYear = $order->expirationyear;
650
+ $card->cvNumber = $order->CVV2;
651
+ $request->card = $card;
652
+
653
+ $soapClient = new CyberSourceSoapClient($wsdl_url, array("merchantID"=>pmpro_getOption("cybersource_merchantid"), "transactionKey"=>pmpro_getOption("cybersource_securitykey")));
654
+ $reply = $soapClient->runTransaction($request);
655
+
656
+ if($reply->reasonCode == "100")
657
+ {
658
+ //success
659
+ return true;
660
+ }
661
+ else
662
+ {
663
+ //error
664
+ $order->errorcode = $reply->reasonCode;
665
+ $order->error = $this->getErrorFromCode($reply->reasonCode);
666
+ $order->shorterror = $this->getErrorFromCode($reply->reasonCode);
667
+ return false;
668
+ }
669
+ }
670
+
671
+ function cancel(&$order)
672
+ {
673
+ //require a subscription id
674
+ if(empty($order->subscription_transaction_id))
675
+ return false;
676
+
677
+ //get wsdl
678
+ $wsdl_url = $this->getWSDL($order);
679
+
680
+ //to store our request
681
+ $request = new stdClass();
682
+
683
+ //which service?
684
+ $paySubscriptionDeleteService = new stdClass();
685
+ $paySubscriptionDeleteService ->run = "true";
686
+ $request->paySubscriptionDeleteService = $paySubscriptionDeleteService ;
687
+
688
+ //which order
689
+ $recurringSubscriptionInfo = new stdClass();
690
+ $recurringSubscriptionInfo->subscriptionID = $order->subscription_transaction_id;
691
+ $request->recurringSubscriptionInfo = $recurringSubscriptionInfo;
692
+
693
+ //merchant id and order code
694
+ $request->merchantID = pmpro_getOption("cybersource_merchantid");
695
+ $request->merchantReferenceCode = $order->code;
696
+
697
+ $soapClient = new CyberSourceSoapClient($wsdl_url, array("merchantID"=>pmpro_getOption("cybersource_merchantid"), "transactionKey"=>pmpro_getOption("cybersource_securitykey")));
698
+ $reply = $soapClient->runTransaction($request);
699
+
700
+ if($reply->reasonCode == "100")
701
+ {
702
+ //success
703
+ $order->updateStatus("cancelled");
704
+ return true;
705
+ }
706
+ else
707
+ {
708
+ //error
709
+ $order->errorcode = $reply->reasonCode;
710
+ $order->error = $this->getErrorFromCode($reply->reasonCode);
711
+ $order->shorterror = $this->getErrorFromCode($reply->reasonCode);
712
+ return false;
713
+ }
714
+ }
715
+
716
+ function getErrorFromCode($code)
717
+ {
718
+ $error_messages = array(
719
+ "100" => "Successful transaction.",
720
+ "101" => "The request is missing one or more required fields.",
721
+ "102" => "One or more fields in the request contains invalid data. Check that your billing address is valid.",
722
+ "104" => "Duplicate order detected.",
723
+ "110" => "Only partial amount was approved.",
724
+ "150" => "Error: General system failure.",
725
+ "151" => "Error: The request was received but there was a server timeout.",
726
+ "152" => "Error: The request was received, but a service did not finish running in time. ",
727
+ "200" => "Address Verification Service (AVS) failure.",
728
+ "201" => "Authorization failed.",
729
+ "202" => "Expired card or invalid expiration date.",
730
+ "203" => "The card was declined.",
731
+ "204" => "Insufficient funds in the account.",
732
+ "205" => "Stolen or lost card.",
733
+ "207" => "Issuing bank unavailable.",
734
+ "208" => "Inactive card or card not authorized for card-not-present transactions.",
735
+ "209" => "American Express Card Identification Digits (CID) did not match.",
736
+ "210" => "The card has reached the credit limit. ",
737
+ "211" => "Invalid card verification number.",
738
+ "221" => "The customer matched an entry on the processors negative file. ",
739
+ "230" => "Card verification (CV) check failed.",
740
+ "231" => "Invalid account number.",
741
+ "232" => "The card type is not accepted by the payment processor.",
742
+ "233" => "General decline by the processor.",
743
+ "234" => "There is a problem with your CyberSource merchant configuration.",
744
+ "235" => "The requested amount exceeds the originally authorized amount.",
745
+ "236" => "Processor failure.",
746
+ "237" => "The authorization has already been reversed.",
747
+ "238" => "The authorization has already been captured.",
748
+ "239" => "The requested transaction amount must match the previous transaction amount.",
749
+ "240" => "The card type sent is invalid or does not correlate with the credit card number.",
750
+ "241" => "The referenced request id is invalid for all follow-on transactions.",
751
+ "242" => "The request ID is invalid.",
752
+ "243" => "The transaction has already been settled or reversed.",
753
+ "246" => "The capture or credit is not voidable because the capture or credit information has already been submitted to your processor. Or, you requested a void for a type of transaction that cannot be voided.",
754
+ "247" => "You requested a credit for a capture that was previously voided.",
755
+ "250" => "Error: The request was received, but there was a timeout at the payment processor.",
756
+ "520" => "Smart Authorization failed."
757
+ );
758
+
759
+ if(isset($error_messages[$code]))
760
+ return $error_messages[$code];
761
+ else
762
+ return "Unknown error.";
763
+ }
764
+ }
classes/gateways/class.pmprogateway_payflowpro.php ADDED
@@ -0,0 +1,448 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/class.pmprogateway.php");
3
+ class PMProGateway_payflowpro
4
+ {
5
+ function PMProGateway_payflowpro($gateway = NULL)
6
+ {
7
+ $this->gateway = $gateway;
8
+ return $this->gateway;
9
+ }
10
+
11
+ function process(&$order)
12
+ {
13
+ if(floatval($order->InitialPayment) == 0)
14
+ {
15
+ //auth first, then process
16
+ $authorization_id = $this->authorize($order);
17
+ if($authorization_id)
18
+ {
19
+ $this->void($order, $authorization_id);
20
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $order->BillingFrequency . " " . $order->BillingPeriod, current_time("timestamp"))) . "T0:0:0";
21
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
22
+ return $this->subscribe($order);
23
+ }
24
+ else
25
+ {
26
+ if(empty($order->error))
27
+ $order->error = __("Unknown error: Authorization failed.", "pmpro");
28
+ return false;
29
+ }
30
+ }
31
+ else
32
+ {
33
+ //charge first payment
34
+ if($this->charge($order))
35
+ {
36
+ //setup recurring billing
37
+ if(pmpro_isLevelRecurring($order->membership_level))
38
+ {
39
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $order->BillingFrequency . " " . $order->BillingPeriod, current_time("timestamp"))) . "T0:0:0";
40
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
41
+ if($this->subscribe($order))
42
+ {
43
+ return true;
44
+ }
45
+ else
46
+ {
47
+ if($this->void($order, $order->payment_transaction_id))
48
+ {
49
+ if(empty($order->error))
50
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
51
+ }
52
+ else
53
+ {
54
+ if(empty($order->error))
55
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
56
+
57
+ $order->error .= " " . __("A partial payment was made that we could not refund. Please contact the site owner immediately to correct this.", "pmpro");
58
+ }
59
+
60
+ return false;
61
+ }
62
+ }
63
+ else
64
+ {
65
+ //only a one time charge
66
+ $order->status = "success"; //saved on checkout page
67
+ $order->saveOrder();
68
+ return true;
69
+ }
70
+ }
71
+ }
72
+ }
73
+
74
+ function authorize(&$order)
75
+ {
76
+ if(empty($order->code))
77
+ $order->code = $order->getRandomCode();
78
+
79
+ //paypal profile stuff
80
+ $nvpStr = "";
81
+
82
+ $nvpStr .="&AMT=1.00";
83
+ $nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
84
+ //$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $order->PaymentAmount;
85
+
86
+ $nvpStr .= "&CUSTIP=" . $_SERVER['REMOTE_ADDR'] . "&INVNUM=" . $order->code;
87
+
88
+ //credit card fields
89
+ if($order->cardtype == "American Express")
90
+ $cardtype = "Amex";
91
+ else
92
+ $cardtype = $order->cardtype;
93
+
94
+ if(!empty($order->accountnumber))
95
+ $nvpStr .= "&ACCT=" . $order->accountnumber . "&EXPDATE=" . $order->expirationmonth . substr($order->expirationyear, 2, 2) . "&CVV2=" . $order->CVV2;
96
+
97
+ //billing address, etc
98
+ if(!empty($order->Address1))
99
+ {
100
+ $nvpStr .= "&EMAIL=" . $order->Email . "&FIRSTNAME=" . $order->FirstName . "&LASTNAME=" . $order->LastName . "&STREET=" . $order->Address1;
101
+
102
+ if($order->Address2)
103
+ $nvpStr .= " " . $order->Address2;
104
+
105
+ $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&BILLTOCOUNTRY=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&PHONENUM=" . $order->billing->phone;
106
+ }
107
+
108
+ //for debugging, let's attach this to the class object
109
+ $this->nvpStr = $nvpStr;
110
+
111
+ $this->httpParsedResponseAr = $this->PPHttpPost('A', $nvpStr);
112
+
113
+ if("0" == strtoupper($this->httpParsedResponseAr["RESULT"])) {
114
+ $order->authorization_id = $this->httpParsedResponseAr['PNREF'];
115
+ $order->updateStatus("authorized");
116
+ return $order->authorization_id;
117
+ } else {
118
+ $order->status = "error";
119
+ $order->errorcode = $this->httpParsedResponseAr['RESULT'];
120
+ $order->error = urldecode($this->httpParsedResponseAr['RESPMSG']);
121
+ $order->shorterror = urldecode($this->httpParsedResponseAr['RESPMSG']);
122
+ return false;
123
+ }
124
+ }
125
+
126
+ function void(&$order, $authorization_id)
127
+ {
128
+ if(empty($authorization_id))
129
+ return false;
130
+
131
+ //paypal profile stuff
132
+ $nvpStr="&ORIGID=" . $authorization_id;
133
+
134
+ $this->httpParsedResponseAr = $this->PPHttpPost('V', $nvpStr);
135
+
136
+ if("0" == strtoupper($this->httpParsedResponseAr["RESULT"])) {
137
+ return true;
138
+ } else {
139
+ $order->status = "error";
140
+ $order->errorcode = $this->httpParsedResponseAr['RESULT'];
141
+ $order->error = urldecode($this->httpParsedResponseAr['RESPMSG']);
142
+ $order->shorterror = urldecode($this->httpParsedResponseAr['RESPMSG']);
143
+ return false;
144
+ }
145
+ }
146
+
147
+ function charge(&$order)
148
+ {
149
+ global $pmpro_currency;
150
+
151
+ if(empty($order->code))
152
+ $order->code = $order->getRandomCode();
153
+
154
+ //taxes on the amount
155
+ $amount = $order->InitialPayment;
156
+ $amount_tax = $order->getTaxForPrice($amount);
157
+ $order->subtotal = $amount;
158
+ $amount = round((float)$amount + (float)$amount_tax, 2);
159
+
160
+ //paypal profile stuff
161
+ $nvpStr = "";
162
+ $nvpStr .="&AMT=" . $amount . "&TAXAMT=" . $amount_tax . "&CURRENCY=" . $pmpro_currency;
163
+ $nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
164
+ //$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $order->PaymentAmount;
165
+
166
+ $nvpStr .= "&CUSTIP=" . $_SERVER['REMOTE_ADDR'] . "&INVNUM=" . $order->code;
167
+
168
+ if(!empty($order->accountnumber))
169
+ $nvpStr .= "&ACCT=" . $order->accountnumber . "&EXPDATE=" . $order->expirationmonth . substr($order->expirationyear, 2, 2) . "&CVV2=" . $order->CVV2;
170
+
171
+ //billing address, etc
172
+ if($order->Address1)
173
+ {
174
+ $nvpStr .= "&EMAIL=" . $order->Email . "&FIRSTNAME=" . $order->FirstName . "&LASTNAME=" . $order->LastName . "&STREET=" . $order->Address1;
175
+
176
+ if($order->Address2)
177
+ $nvpStr .= " " . $order->Address2;
178
+
179
+ $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&BILLTOCOUNTRY=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&PHONENUM=" . $order->billing->phone;
180
+ }
181
+
182
+ $this->nvpStr = $nvpStr;
183
+ $this->httpParsedResponseAr = $this->PPHttpPost('S', $nvpStr);
184
+
185
+ if("0" == strtoupper($this->httpParsedResponseAr["RESULT"])) {
186
+ $order->payment_transaction_id = $this->httpParsedResponseAr['PNREF'];
187
+ $order->updateStatus("success");
188
+ return true;
189
+ } else {
190
+ $order->status = "error";
191
+ $order->errorcode = $this->httpParsedResponseAr['RESULT'];
192
+ $order->error = urldecode($this->httpParsedResponseAr['RESPMSG']);
193
+ $order->shorterror = urldecode($this->httpParsedResponseAr['RESPMSG']);
194
+ return false;
195
+ }
196
+ }
197
+
198
+ function subscribe(&$order)
199
+ {
200
+ global $pmpro_currency;
201
+
202
+ if(empty($order->code))
203
+ $order->code = $order->getRandomCode();
204
+
205
+ //filter order before subscription. use with care.
206
+ $order = apply_filters("pmpro_subscribe_order", $order, $this);
207
+
208
+ //taxes on the amount
209
+ $amount = $order->PaymentAmount;
210
+ $amount_tax = $order->getTaxForPrice($amount);
211
+ $amount = round((float)$amount + (float)$amount_tax, 2);
212
+
213
+ if($order->BillingPeriod == "Week")
214
+ $payperiod = "WEEK";
215
+ elseif($order->BillingPeriod == "Month")
216
+ $payperiod = "MONT";
217
+ elseif($order->BillingPeriod == "Year")
218
+ $payperiod = "YEAR";
219
+
220
+ //paypal profile stuff
221
+ $nvpStr = "&ACTION=A";
222
+ $nvpStr .="&AMT=" . $amount . "&TAXAMT=" . $amount_tax . "&CURRENCY=" . $pmpro_currency;
223
+ $nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
224
+ //$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $order->PaymentAmount;
225
+
226
+ $nvpStr .= "&PROFILENAME=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127));
227
+
228
+ $nvpStr .= "&PAYPERIOD=" . $payperiod;
229
+
230
+ $nvpStr .= "&CUSTIP=" . $_SERVER['REMOTE_ADDR']; // . "&INVNUM=" . $order->code;
231
+
232
+ //if billing cycles are defined
233
+ if(!empty($order->TotalBillingCycles))
234
+ $nvpStr .= "&TERM=" . $order->TotalBillingCycles;
235
+ else
236
+ $nvpStr .= "&TERM=0";
237
+
238
+ if(!empty($order->accountnumber))
239
+ $nvpStr .= "&ACCT=" . $order->accountnumber . "&EXPDATE=" . $order->expirationmonth . substr($order->expirationyear, 2, 2) . "&CVV2=" . $order->CVV2;
240
+
241
+ /*
242
+ Let's figure out the start date. There are two parts.
243
+ 1. We need to add the billing period to the start date to account for the initial payment.
244
+ 2. We can allow for free trials by further delaying the start date of the subscription.
245
+ */
246
+ if($order->BillingPeriod == "Year")
247
+ $trial_period_days = $order->BillingFrequency * 365; //annual
248
+ elseif($order->BillingPeriod == "Day")
249
+ $trial_period_days = $order->BillingFrequency * 1; //daily
250
+ elseif($order->BillingPeriod == "Week")
251
+ $trial_period_days = $order->BillingFrequency * 7; //weekly
252
+ else
253
+ $trial_period_days = $order->BillingFrequency * 30; //assume monthly
254
+
255
+ //convert to a profile start date
256
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $trial_period_days . " Day", current_time("timestamp"))) . "T0:0:0";
257
+
258
+ //filter the start date
259
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
260
+
261
+ //convert back to days
262
+ $trial_period_days = ceil(abs(strtotime(date("Y-m-d"), current_time('timestamp')) - strtotime($order->ProfileStartDate, current_time("timestamp"))) / 86400);
263
+
264
+ //now add the actual trial set by the site
265
+ if(!empty($order->TrialBillingCycles))
266
+ {
267
+ $trialOccurrences = (int)$order->TrialBillingCycles;
268
+ if($order->BillingPeriod == "Year")
269
+ $trial_period_days = $trial_period_days + (365 * $order->BillingFrequency * $trialOccurrences); //annual
270
+ elseif($order->BillingPeriod == "Day")
271
+ $trial_period_days = $trial_period_days + (1 * $order->BillingFrequency * $trialOccurrences); //daily
272
+ elseif($order->BillingPeriod == "Week")
273
+ $trial_period_days = $trial_period_days + (7 * $order->BillingFrequency * $trialOccurrences); //weekly
274
+ else
275
+ $trial_period_days = $trial_period_days + (30 * $order->BillingFrequency * $trialOccurrences); //assume monthly
276
+ }
277
+
278
+ //convert back into a date
279
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $trial_period_days . " Day", current_time("timestamp"))) . "T0:0:0";
280
+
281
+ //start date
282
+ $nvpStr .= "&START=" . date("mdY", strtotime($order->ProfileStartDate));
283
+
284
+ if(!empty($order->accountnumber))
285
+ $nvpStr .= "&ACCT=" . $order->accountnumber . "&EXPDATE=" . $order->expirationmonth . substr($order->expirationyear, 2, 2) . "&CVV2=" . $order->CVV2;
286
+
287
+ //billing address, etc
288
+ if($order->Address1)
289
+ {
290
+ $nvpStr .= "&EMAIL=" . $order->Email . "&FIRSTNAME=" . $order->FirstName . "&LASTNAME=" . $order->LastName . "&STREET=" . $order->Address1;
291
+
292
+ if($order->Address2)
293
+ $nvpStr .= " " . $order->Address2;
294
+
295
+ $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&BILLTOCOUNTRY=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&PHONENUM=" . $order->billing->phone;
296
+ }
297
+
298
+ $this->nvpStr = $nvpStr;
299
+ $this->httpParsedResponseAr = $this->PPHttpPost('R', $nvpStr);
300
+
301
+ if("0" == strtoupper($this->httpParsedResponseAr["RESULT"])) {
302
+ $order->subscription_transaction_id = $this->httpParsedResponseAr['PROFILEID'];
303
+ $order->status = "success";
304
+ return true;
305
+ } else {
306
+ $order->status = "error";
307
+ $order->errorcode = $this->httpParsedResponseAr['RESULT'];
308
+ $order->error = urldecode($this->httpParsedResponseAr['RESPMSG']);
309
+ $order->shorterror = urldecode($this->httpParsedResponseAr['RESPMSG']);
310
+ return false;
311
+ }
312
+ }
313
+
314
+ function update(&$order)
315
+ {
316
+ $order->getMembershipLevel();
317
+
318
+ //paypal profile stuff
319
+ $nvpStr = "&ORIGPROFILEID=" . $order->subscription_transaction_id . "&ACTION=M";
320
+ $nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
321
+
322
+ $nvpStr .= "&PROFILENAME=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127));
323
+
324
+ $nvpStr .= "&CUSTIP=" . $_SERVER['REMOTE_ADDR']; // . "&INVNUM=" . $order->code;
325
+
326
+ if(!empty($order->accountnumber))
327
+ $nvpStr .= "&ACCT=" . $order->accountnumber . "&EXPDATE=" . $order->expirationmonth . substr($order->expirationyear, 2, 2) . "&CVV2=" . $order->CVV2;
328
+
329
+ //billing address, etc
330
+ if($order->Address1)
331
+ {
332
+ $nvpStr .= "&EMAIL=" . $order->Email . "&FIRSTNAME=" . $order->FirstName . "&LASTNAME=" . $order->LastName . "&STREET=" . $order->Address1;
333
+
334
+ if($order->Address2)
335
+ $nvpStr .= " " . $order->Address2;
336
+
337
+ $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&BILLTOCOUNTRY=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&PHONENUM=" . $order->billing->phone;
338
+ }
339
+
340
+ $this->nvpStr = $nvpStr;
341
+ $this->httpParsedResponseAr = $this->PPHttpPost('R', $nvpStr);
342
+
343
+ if("0" == strtoupper($this->httpParsedResponseAr["RESULT"])) {
344
+ $order->subscription_transaction_id = $this->httpParsedResponseAr['PROFILEID'];
345
+ $order->updateStatus("success");
346
+ return true;
347
+ } else {
348
+ $order->status = "error";
349
+ $order->errorcode = $this->httpParsedResponseAr['RESULT'];
350
+ $order->error = urldecode($this->httpParsedResponseAr['RESPMSG']);
351
+ $order->shorterror = urldecode($this->httpParsedResponseAr['RESPMSG']);
352
+ return false;
353
+ }
354
+ }
355
+
356
+ function cancel(&$order)
357
+ {
358
+ //require a subscription id
359
+ if(empty($order->subscription_transaction_id))
360
+ return false;
361
+
362
+ //paypal profile stuff
363
+ $nvpStr = "&ORIGPROFILEID=" . $order->subscription_transaction_id . "&ACTION=C";
364
+
365
+ $this->nvpStr = $nvpStr;
366
+ $this->httpParsedResponseAr = $this->PPHttpPost('R', $nvpStr);
367
+
368
+ if("0" == strtoupper($this->httpParsedResponseAr["RESULT"]))
369
+ {
370
+ $order->updateStatus("cancelled");
371
+ return true;
372
+ }
373
+ else
374
+ {
375
+ $order->status = "error";
376
+ $order->errorcode = $this->httpParsedResponseAr['RESULT'];
377
+ $order->error = urldecode($this->httpParsedResponseAr['RESPMSG']);
378
+ $order->shorterror = urldecode($this->httpParsedResponseAr['RESPMSG']);
379
+ return false;
380
+ }
381
+ }
382
+
383
+ /**
384
+ * PAYPAL Function
385
+ * Send HTTP POST Request
386
+ *
387
+ * @param string The API method name
388
+ * @param string The POST Message fields in &name=value pair format
389
+ * @return array Parsed HTTP Response body
390
+ */
391
+ function PPHttpPost($methodName_, $nvpStr_) {
392
+ global $gateway_environment;
393
+ $environment = $gateway_environment;
394
+
395
+ $PARTNER = pmpro_getOption("payflow_partner");
396
+ $VENDOR = pmpro_getOption("payflow_vendor");
397
+ $USER = pmpro_getOption("payflow_user");
398
+ $PWD = pmpro_getOption("payflow_pwd");
399
+ $API_Endpoint = "https://payflowpro.paypal.com";
400
+ if("sandbox" === $environment || "beta-sandbox" === $environment) {
401
+ $API_Endpoint = "https://pilot-payflowpro.paypal.com";
402
+ }
403
+
404
+ $version = urlencode('4');
405
+
406
+ // setting the curl parameters.
407
+ $ch = curl_init();
408
+ curl_setopt($ch, CURLOPT_URL, $API_Endpoint);
409
+ curl_setopt($ch, CURLOPT_VERBOSE, 1);
410
+
411
+ // turning off the server and peer verification(TrustManager Concept).
412
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
413
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
414
+
415
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
416
+ curl_setopt($ch, CURLOPT_POST, 1);
417
+
418
+ // NVPRequest for submitting to server
419
+ $nvpreq = "TRXTYPE=" . urlencode($methodName_) . "&TENDER=C&PARTNER=" . urlencode($PARTNER) . "&VENDOR=" . urlencode($VENDOR) . "&USER=" . urlencode($USER) . "&PWD=" . urlencode($PWD) . "&VERBOSITY=medium" . $nvpStr_;
420
+
421
+ // setting the nvpreq as POST FIELD to curl
422
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $nvpreq);
423
+
424
+ // getting response from server
425
+ $httpResponse = curl_exec($ch);
426
+
427
+ if(empty($httpResponse)) {
428
+ exit("$methodName_ failed: ".curl_error($ch).'('.curl_errno($ch).')');
429
+ }
430
+
431
+ // Extract the RefundTransaction response details
432
+ $httpResponseAr = explode("&", $httpResponse);
433
+
434
+ $httpParsedResponseAr = array();
435
+ foreach ($httpResponseAr as $i => $value) {
436
+ $tmpAr = explode("=", $value);
437
+ if(sizeof($tmpAr) > 1) {
438
+ $httpParsedResponseAr[$tmpAr[0]] = $tmpAr[1];
439
+ }
440
+ }
441
+
442
+ if((0 == sizeof($httpParsedResponseAr)) || !array_key_exists('RESULT', $httpParsedResponseAr)) {
443
+ exit("Invalid HTTP Response for POST request($nvpreq) to $API_Endpoint.");
444
+ }
445
+
446
+ return $httpParsedResponseAr;
447
+ }
448
+ }
classes/gateways/class.pmprogateway_paypal.php ADDED
@@ -0,0 +1,456 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/class.pmprogateway.php");
3
+ class PMProGateway_paypal
4
+ {
5
+ function PMProGateway_paypal($gateway = NULL)
6
+ {
7
+ $this->gateway = $gateway;
8
+ return $this->gateway;
9
+ }
10
+
11
+ function process(&$order)
12
+ {
13
+ if(floatval($order->InitialPayment) == 0)
14
+ {
15
+ //auth first, then process
16
+ $authorization_id = $this->authorize($order);
17
+ if($authorization_id)
18
+ {
19
+ $this->void($order, $authorization_id);
20
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $order->BillingFrequency . " " . $order->BillingPeriod, current_time("timestamp"))) . "T0:0:0";
21
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
22
+ return $this->subscribe($order);
23
+ }
24
+ else
25
+ {
26
+ if(empty($order->error))
27
+ $order->error = __("Unknown error: Authorization failed.", "pmpro");
28
+ return false;
29
+ }
30
+ }
31
+ else
32
+ {
33
+ //charge first payment
34
+ if($this->charge($order))
35
+ {
36
+ //setup recurring billing
37
+ if(pmpro_isLevelRecurring($order->membership_level))
38
+ {
39
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $order->BillingFrequency . " " . $order->BillingPeriod, current_time("timestamp"))) . "T0:0:0";
40
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
41
+ if($this->subscribe($order))
42
+ {
43
+ return true;
44
+ }
45
+ else
46
+ {
47
+ if($this->refund($order, $order->payment_transaction_id))
48
+ {
49
+ if(empty($order->error))
50
+ $order->error = __("Unknown error: Payment failed.", "pmpro");
51
+ }
52
+ else
53
+ {
54
+ if(empty($order->error))
55
+ $order->error = "Unknown error: Payment failed.";
56
+
57
+ $order->error .= " " . __("A partial payment was made that we could not refund. Please contact the site owner immediately to correct this.", "pmpro");
58
+ }
59
+
60
+ return false;
61
+ }
62
+ }
63
+ else
64
+ {
65
+ //only a one time charge
66
+ $order->status = "success"; //saved on checkout page
67
+ $order->saveOrder();
68
+ return true;
69
+ }
70
+ }
71
+ }
72
+ }
73
+
74
+ function authorize(&$order)
75
+ {
76
+ if(empty($order->code))
77
+ $order->code = $order->getRandomCode();
78
+
79
+ //paypal profile stuff
80
+ $nvpStr = "";
81
+ if(!empty($order->Token))
82
+ $nvpStr .= "&TOKEN=" . $order->Token;
83
+ $nvpStr .="&AMT=1.00&CURRENCYCODE=" . pmpro_getOption("currency");
84
+ $nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
85
+ //$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $order->PaymentAmount;
86
+
87
+ $nvpStr .= "&PAYMENTACTION=Authorization&IPADDRESS=" . $_SERVER['REMOTE_ADDR'] . "&INVNUM=" . $order->code;
88
+
89
+ //credit card fields
90
+ if($order->cardtype == "American Express")
91
+ $cardtype = "Amex";
92
+ else
93
+ $cardtype = $order->cardtype;
94
+
95
+ if(!empty($cardtype))
96
+ $nvpStr .= "&CREDITCARDTYPE=" . $cardtype . "&ACCT=" . $order->accountnumber . "&EXPDATE=" . $order->ExpirationDate . "&CVV2=" . $order->CVV2;
97
+
98
+ //Maestro/Solo card fields. (Who uses these?) :)
99
+ if(!empty($order->StartDate))
100
+ $nvpStr .= "&STARTDATE=" . $order->StartDate . "&ISSUENUMBER=" . $order->IssueNumber;
101
+
102
+ //billing address, etc
103
+ if(!empty($order->Address1))
104
+ {
105
+ $nvpStr .= "&EMAIL=" . $order->Email . "&FIRSTNAME=" . $order->FirstName . "&LASTNAME=" . $order->LastName . "&STREET=" . $order->Address1;
106
+
107
+ if($order->Address2)
108
+ $nvpStr .= "&STREET2=" . $order->Address2;
109
+
110
+ $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&COUNTRYCODE=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&SHIPTOPHONENUM=" . $order->billing->phone;
111
+ }
112
+
113
+ //for debugging, let's attach this to the class object
114
+ $this->nvpStr = $nvpStr;
115
+
116
+ $this->httpParsedResponseAr = $this->PPHttpPost('DoDirectPayment', $nvpStr);
117
+
118
+ if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
119
+ $order->authorization_id = $this->httpParsedResponseAr['TRANSACTIONID'];
120
+ $order->updateStatus("authorized");
121
+ return $order->authorization_id;
122
+ } else {
123
+ $order->status = "error";
124
+ $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
125
+ $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
126
+ $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
127
+ return false;
128
+ }
129
+ }
130
+
131
+ function void(&$order, $authorization_id)
132
+ {
133
+ if(empty($authorization_id))
134
+ return false;
135
+
136
+ //paypal profile stuff
137
+ $nvpStr="&AUTHORIZATIONID=" . $authorization_id . "&NOTE=Voiding an authorization for a recurring payment setup.";
138
+
139
+ $this->httpParsedResponseAr = $this->PPHttpPost('DoVoid', $nvpStr);
140
+
141
+ if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
142
+ return true;
143
+ } else {
144
+ $order->status = "error";
145
+ $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
146
+ $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
147
+ $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
148
+ return false;
149
+ }
150
+ }
151
+
152
+ function refund(&$order, $transaction_id)
153
+ {
154
+ if(empty($transaction_id))
155
+ return false;
156
+
157
+ //paypal profile stuff
158
+ $nvpStr="&TRANSACTIONID=" . $transaction_id . "&NOTE=Refunding a charge.";
159
+
160
+ $this->httpParsedResponseAr = $this->PPHttpPost('RefundTransaction', $nvpStr);
161
+
162
+ if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
163
+ return true;
164
+ } else {
165
+ $order->status = "error";
166
+ $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
167
+ $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
168
+ $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
169
+ return false;
170
+ }
171
+ }
172
+
173
+ function charge(&$order)
174
+ {
175
+ global $pmpro_currency;
176
+
177
+ if(empty($order->code))
178
+ $order->code = $order->getRandomCode();
179
+
180
+ //taxes on the amount
181
+ $amount = $order->InitialPayment;
182
+ $amount_tax = $order->getTaxForPrice($amount);
183
+ $order->subtotal = $amount;
184
+ $amount = round((float)$amount + (float)$amount_tax, 2);
185
+
186
+ //paypal profile stuff
187
+ $nvpStr = "";
188
+ if(!empty($order->Token))
189
+ $nvpStr .= "&TOKEN=" . $order->Token;
190
+ $nvpStr .="&AMT=" . $amount . "&ITEMAMT=" . $order->InitialPayment . "&TAXAMT=" . $amount_tax . "&CURRENCYCODE=" . $pmpro_currency;
191
+ $nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
192
+ //$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $order->PaymentAmount;
193
+
194
+ $nvpStr .= "&PAYMENTACTION=Sale&IPADDRESS=" . $_SERVER['REMOTE_ADDR'] . "&INVNUM=" . $order->code;
195
+
196
+ //credit card fields
197
+ if($order->cardtype == "American Express")
198
+ $cardtype = "Amex";
199
+ else
200
+ $cardtype = $order->cardtype;
201
+
202
+ if(!empty($cardtype))
203
+ $nvpStr .= "&CREDITCARDTYPE=" . $cardtype . "&ACCT=" . $order->accountnumber . "&EXPDATE=" . $order->ExpirationDate . "&CVV2=" . $order->CVV2;
204
+
205
+ //Maestro/Solo card fields. (Who uses these?) :)
206
+ if(!empty($order->StartDate))
207
+ $nvpStr .= "&STARTDATE=" . $order->StartDate . "&ISSUENUMBER=" . $order->IssueNumber;
208
+
209
+ //billing address, etc
210
+ if($order->Address1)
211
+ {
212
+ $nvpStr .= "&EMAIL=" . $order->Email . "&FIRSTNAME=" . $order->FirstName . "&LASTNAME=" . $order->LastName . "&STREET=" . $order->Address1;
213
+
214
+ if($order->Address2)
215
+ $nvpStr .= "&STREET2=" . $order->Address2;
216
+
217
+ $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&COUNTRYCODE=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&SHIPTOPHONENUM=" . $order->billing->phone;
218
+ }
219
+
220
+ $this->httpParsedResponseAr = $this->PPHttpPost('DoDirectPayment', $nvpStr);
221
+
222
+ if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
223
+ $order->payment_transaction_id = $this->httpParsedResponseAr['TRANSACTIONID'];
224
+ $order->updateStatus("success");
225
+ return true;
226
+ } else {
227
+ $order->status = "error";
228
+ $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
229
+ $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
230
+ $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
231
+ return false;
232
+ }
233
+ }
234
+
235
+ function subscribe(&$order)
236
+ {
237
+ global $pmpro_currency;
238
+
239
+ if(empty($order->code))
240
+ $order->code = $order->getRandomCode();
241
+
242
+ //filter order before subscription. use with care.
243
+ $order = apply_filters("pmpro_subscribe_order", $order, $this);
244
+
245
+ //taxes on the amount
246
+ $amount = $order->PaymentAmount;
247
+ $amount_tax = $order->getTaxForPrice($amount);
248
+ $amount = round((float)$amount + (float)$amount_tax, 2);
249
+
250
+ //paypal profile stuff
251
+ $nvpStr = "";
252
+ if(!empty($order->Token))
253
+ $nvpStr .= "&TOKEN=" . $order->Token;
254
+ $nvpStr .="&AMT=" . $order->PaymentAmount . "&TAXAMT=" . $amount_tax . "&CURRENCYCODE=" . $pmpro_currency . "&PROFILESTARTDATE=" . $order->ProfileStartDate;
255
+ $nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLAMT=AddToNextBilling";
256
+ $nvpStr .= "&DESC=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127));
257
+ $nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
258
+ //$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $order->PaymentAmount;
259
+
260
+ //if billing cycles are defined
261
+ if(!empty($order->TotalBillingCycles))
262
+ $nvpStr .= "&TOTALBILLINGCYCLES=" . $order->TotalBillingCycles;
263
+
264
+ //if a trial period is defined
265
+ if(!empty($order->TrialBillingPeriod))
266
+ {
267
+ $trial_amount = $order->TrialAmount;
268
+ $trial_tax = $order->getTaxForPrice($trial_amount);
269
+ $trial_amount = round((float)$trial_amount + (float)$trial_tax, 2);
270
+
271
+ $nvpStr .= "&TRIALBILLINGPERIOD=" . $order->TrialBillingPeriod . "&TRIALBILLINGFREQUENCY=" . $order->TrialBillingFrequency . "&TRIALAMT=" . $trial_amount;
272
+ }
273
+ if(!empty($order->TrialBillingCycles))
274
+ $nvpStr .= "&TRIALTOTALBILLINGCYCLES=" . $order->TrialBillingCycles;
275
+
276
+ //credit card fields
277
+ if($order->cardtype == "American Express")
278
+ $cardtype = "Amex";
279
+ else
280
+ $cardtype = $order->cardtype;
281
+
282
+ if($cardtype)
283
+ $nvpStr .= "&CREDITCARDTYPE=" . $cardtype . "&ACCT=" . $order->accountnumber . "&EXPDATE=" . $order->ExpirationDate . "&CVV2=" . $order->CVV2;
284
+
285
+ //Maestro/Solo card fields. (Who uses these?) :)
286
+ if(!empty($order->StartDate))
287
+ $nvpStr .= "&STARTDATE=" . $order->StartDate . "&ISSUENUMBER=" . $order->IssueNumber;
288
+
289
+ //billing address, etc
290
+ if($order->Address1)
291
+ {
292
+ $nvpStr .= "&EMAIL=" . $order->Email . "&FIRSTNAME=" . $order->FirstName . "&LASTNAME=" . $order->LastName . "&STREET=" . $order->Address1;
293
+
294
+ if($order->Address2)
295
+ $nvpStr .= "&STREET2=" . $order->Address2;
296
+
297
+ $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&COUNTRYCODE=" . $order->billing->country . "&ZIP=" . $order->billing->zip . "&SHIPTOPHONENUM=" . $order->billing->phone;
298
+ }
299
+
300
+ //for debugging let's add this to the class object
301
+ $this->nvpStr = $nvpStr;
302
+
303
+ $this->httpParsedResponseAr = $this->PPHttpPost('CreateRecurringPaymentsProfile', $nvpStr);
304
+
305
+ if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
306
+ $order->status = "success";
307
+ $order->subscription_transaction_id = urldecode($this->httpParsedResponseAr['PROFILEID']);
308
+ return true;
309
+ //exit('CreateRecurringPaymentsProfile Completed Successfully: '.print_r($this->httpParsedResponseAr, true));
310
+ } else {
311
+ $order->status = "error";
312
+ $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
313
+ $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
314
+ $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
315
+ return false;
316
+ //exit('CreateRecurringPaymentsProfile failed: ' . print_r($httpParsedResponseAr, true));
317
+ }
318
+ }
319
+
320
+ function update(&$order)
321
+ {
322
+ //paypal profile stuff
323
+ $nvpStr = "";
324
+ $nvpStr .= "&PROFILEID=" . $order->subscription_transaction_id;
325
+
326
+ //credit card fields
327
+ if($order->cardtype == "American Express")
328
+ $cardtype = "Amex";
329
+ else
330
+ $cardtype = $order->cardtype;
331
+
332
+ //credit card fields
333
+ if($cardtype)
334
+ $nvpStr .= "&CREDITCARDTYPE=" . $cardtype . "&ACCT=" . $order->accountnumber . "&EXPDATE=" . $order->ExpirationDate . "&CVV2=" . $order->CVV2;
335
+
336
+ //Maestro/Solo card fields. (Who uses these?) :)
337
+ if($order->StartDate)
338
+ $nvpStr .= "&STARTDATE=" . $order->StartDate . "&ISSUENUMBER=" . $order->IssueNumber;
339
+
340
+ //billing address, etc
341
+ if($order->Address1)
342
+ {
343
+ $nvpStr .= "&EMAIL=" . $order->Email . "&FIRSTNAME=" . $order->FirstName . "&LASTNAME=" . $order->LastName . "&STREET=" . $order->Address1;
344
+
345
+ if($order->Address2)
346
+ $nvpStr .= "&STREET2=" . $order->Address2;
347
+
348
+ $nvpStr .= "&CITY=" . $order->billing->city . "&STATE=" . $order->billing->state . "&COUNTRYCODE=" . $order->billing->country . "&ZIP=" . $order->billing->zip;
349
+ }
350
+
351
+ $this->httpParsedResponseAr = $this->PPHttpPost('UpdateRecurringPaymentsProfile', $nvpStr);
352
+
353
+ if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
354
+ $order->status = "success";
355
+ $order->subscription_transaction_id = urldecode($this->httpParsedResponseAr['PROFILEID']);
356
+ return true;
357
+ //exit('CreateRecurringPaymentsProfile Completed Successfully: '.print_r($this->httpParsedResponseAr, true));
358
+ } else {
359
+ $order->status = "error";
360
+ $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
361
+ $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
362
+ $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
363
+ return false;
364
+ //exit('CreateRecurringPaymentsProfile failed: ' . print_r($httpParsedResponseAr, true));
365
+ }
366
+ }
367
+
368
+ function cancel(&$order)
369
+ {
370
+ //paypal profile stuff
371
+ $nvpStr = "";
372
+ $nvpStr .= "&PROFILEID=" . urlencode($order->subscription_transaction_id) . "&ACTION=Cancel&NOTE=" . urlencode("User requested cancel.");
373
+
374
+ $this->httpParsedResponseAr = $this->PPHttpPost('ManageRecurringPaymentsProfileStatus', $nvpStr);
375
+
376
+ if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"]))
377
+ {
378
+ $order->updateStatus("cancelled");
379
+ return true;
380
+ }
381
+ else
382
+ {
383
+ $order->status = "error";
384
+ $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
385
+ $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']) . ". " . __("Please contact the site owner or cancel your subscription from within PayPal to make sure you are not charged going forward.", "pmpro");
386
+ $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
387
+
388
+ return false;
389
+ }
390
+ }
391
+
392
+ /**
393
+ * PAYPAL Function
394
+ * Send HTTP POST Request
395
+ *
396
+ * @param string The API method name
397
+ * @param string The POST Message fields in &name=value pair format
398
+ * @return array Parsed HTTP Response body
399
+ */
400
+ function PPHttpPost($methodName_, $nvpStr_) {
401
+ global $gateway_environment;
402
+ $environment = $gateway_environment;
403
+
404
+ $API_UserName = pmpro_getOption("apiusername");
405
+ $API_Password = pmpro_getOption("apipassword");
406
+ $API_Signature = pmpro_getOption("apisignature");
407
+ $API_Endpoint = "https://api-3t.paypal.com/nvp";
408
+ if("sandbox" === $environment || "beta-sandbox" === $environment) {
409
+ $API_Endpoint = "https://api-3t.$environment.paypal.com/nvp";
410
+ }
411
+
412
+ $version = urlencode('72.0');
413
+
414
+ // setting the curl parameters.
415
+ $ch = curl_init();
416
+ curl_setopt($ch, CURLOPT_URL, $API_Endpoint);
417
+ curl_setopt($ch, CURLOPT_VERBOSE, 1);
418
+
419
+ // turning off the server and peer verification(TrustManager Concept).
420
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
421
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
422
+
423
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
424
+ curl_setopt($ch, CURLOPT_POST, 1);
425
+
426
+ // NVPRequest for submitting to server
427
+ $nvpreq = "METHOD=" . urlencode($methodName_) . "&VERSION=" . urlencode($version) . "&PWD=" . urlencode($API_Password) . "&USER=" . urlencode($API_UserName) . "&SIGNATURE=" . urlencode($API_Signature) . $nvpStr_;
428
+
429
+ // setting the nvpreq as POST FIELD to curl
430
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $nvpreq);
431
+
432
+ // getting response from server
433
+ $httpResponse = curl_exec($ch);
434
+
435
+ if(empty($httpResponse)) {
436
+ exit("$methodName_ failed: ".curl_error($ch).'('.curl_errno($ch).')');
437
+ }
438
+
439
+ // Extract the RefundTransaction response details
440
+ $httpResponseAr = explode("&", $httpResponse);
441
+
442
+ $httpParsedResponseAr = array();
443
+ foreach ($httpResponseAr as $i => $value) {
444
+ $tmpAr = explode("=", $value);
445
+ if(sizeof($tmpAr) > 1) {
446
+ $httpParsedResponseAr[$tmpAr[0]] = $tmpAr[1];
447
+ }
448
+ }
449
+
450
+ if((0 == sizeof($httpParsedResponseAr)) || !array_key_exists('ACK', $httpParsedResponseAr)) {
451
+ exit("Invalid HTTP Response for POST request($nvpreq) to $API_Endpoint.");
452
+ }
453
+
454
+ return $httpParsedResponseAr;
455
+ }
456
+ }
classes/gateways/class.pmprogateway_paypalexpress.php ADDED
@@ -0,0 +1,400 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/class.pmprogateway.php");
3
+ class PMProGateway_paypalexpress
4
+ {
5
+ function PMProGateway_paypalexpress($gateway = NULL)
6
+ {
7
+ $this->gateway = $gateway;
8
+ return $this->gateway;
9
+ }
10
+
11
+ function process(&$order)
12
+ {
13
+ if(pmpro_isLevelRecurring($order->membership_level))
14
+ {
15
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $order->BillingFrequency . " " . $order->BillingPeriod, current_time("timestamp"))) . "T0:0:0";
16
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
17
+ return $this->subscribe($order);
18
+ }
19
+ else
20
+ return $this->charge($order);
21
+ }
22
+
23
+ //PayPal Express, this is run first to authorize from PayPal
24
+ function setExpressCheckout(&$order)
25
+ {
26
+ global $pmpro_currency;
27
+
28
+ if(empty($order->code))
29
+ $order->code = $order->getRandomCode();
30
+
31
+ //clean up a couple values
32
+ $order->payment_type = "PayPal Express";
33
+ $order->CardType = "";
34
+ $order->cardtype = "";
35
+
36
+ //taxes on initial amount
37
+ $initial_payment = $order->InitialPayment;
38
+ $initial_payment_tax = $order->getTaxForPrice($initial_payment);
39
+ $initial_payment = round((float)$initial_payment + (float)$initial_payment_tax, 2);
40
+
41
+ //taxes on the amount
42
+ $amount = $order->PaymentAmount;
43
+ $amount_tax = $order->getTaxForPrice($amount);
44
+ $amount = round((float)$amount + (float)$amount_tax, 2);
45
+
46
+ //paypal profile stuff
47
+ $nvpStr = "";
48
+ $nvpStr .="&AMT=" . $initial_payment . "&CURRENCYCODE=" . $pmpro_currency;
49
+ if(!empty($order->ProfileStartDate) && strtotime($order->ProfileStartDate, current_time("timestamp")) > 0)
50
+ $nvpStr .= "&PROFILESTARTDATE=" . $order->ProfileStartDate;
51
+ if(!empty($order->BillingFrequency))
52
+ $nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLAMT=AddToNextBilling&L_BILLINGTYPE0=RecurringPayments";
53
+ $nvpStr .= "&DESC=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127));
54
+ $nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
55
+ $nvpStr .= "&NOSHIPPING=1&L_BILLINGAGREEMENTDESCRIPTION0=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127)) . "&L_PAYMENTTYPE0=Any";
56
+
57
+ //if billing cycles are defined
58
+ if(!empty($order->TotalBillingCycles))
59
+ $nvpStr .= "&TOTALBILLINGCYCLES=" . $order->TotalBillingCycles;
60
+
61
+ //if a trial period is defined
62
+ if(!empty($order->TrialBillingPeriod))
63
+ {
64
+ $trial_amount = $order->TrialAmount;
65
+ $trial_tax = $order->getTaxForPrice($trial_amount);
66
+ $trial_amount = round((float)$trial_amount + (float)$trial_tax, 2);
67
+
68
+ $nvpStr .= "&TRIALBILLINGPERIOD=" . $order->TrialBillingPeriod . "&TRIALBILLINGFREQUENCY=" . $order->TrialBillingFrequency . "&TRIALAMT=" . $trial_amount;
69
+ }
70
+ if(!empty($order->TrialBillingCycles))
71
+ $nvpStr .= "&TRIALTOTALBILLINGCYCLES=" . $order->TrialBillingCycles;
72
+
73
+ if(!empty($order->discount_code))
74
+ {
75
+ $nvpStr .= "&ReturnUrl=" . urlencode(pmpro_url("checkout", "?level=" . $order->membership_level->id . "&discount_code=" . $order->discount_code . "&review=" . $order->code));
76
+ }
77
+ else
78
+ {
79
+ $nvpStr .= "&ReturnUrl=" . urlencode(pmpro_url("checkout", "?level=" . $order->membership_level->id . "&review=" . $order->code));
80
+ }
81
+
82
+ $additional_parameters = apply_filters("pmpro_paypal_express_return_url_parameters", array());
83
+ if(!empty($additional_parameters))
84
+ {
85
+ foreach($additional_parameters as $key => $value)
86
+ $nvpStr .= urlencode("&" . $key . "=" . $value);
87
+ }
88
+
89
+ $nvpStr .= "&CANCELURL=" . urlencode(pmpro_url("levels"));
90
+
91
+ $account_optional = apply_filters('pmpro_paypal_account_optional', true);
92
+ if ($account_optional)
93
+ $nvpStr .= '&SOLUTIONTYPE=Sole&LANDINGPAGE=Billing';
94
+
95
+ $nvpStr = apply_filters("pmpro_set_express_checkout_nvpstr", $nvpStr, $order);
96
+
97
+ ///echo str_replace("&", "&<br />", $nvpStr);
98
+ ///exit;
99
+
100
+ $this->httpParsedResponseAr = $this->PPHttpPost('SetExpressCheckout', $nvpStr);
101
+
102
+ if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
103
+ $order->status = "token";
104
+ $order->paypal_token = urldecode($this->httpParsedResponseAr['TOKEN']);
105
+
106
+ //update order
107
+ $order->saveOrder();
108
+
109
+ //redirect to paypal
110
+ $paypal_url = "https://www.paypal.com/webscr&cmd=_express-checkout&useraction=commit&token=" . $this->httpParsedResponseAr['TOKEN'];
111
+ $environment = pmpro_getOption("gateway_environment");
112
+ if("sandbox" === $environment || "beta-sandbox" === $environment)
113
+ {
114
+ $paypal_url = "https://www.sandbox.paypal.com/webscr&useraction=commit&cmd=_express-checkout&token=" . $this->httpParsedResponseAr['TOKEN'];
115
+ }
116
+
117
+ wp_redirect($paypal_url);
118
+ exit;
119
+
120
+ //exit('SetExpressCheckout Completed Successfully: '.print_r($this->httpParsedResponseAr, true));
121
+ } else {
122
+ $order->status = "error";
123
+ $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
124
+ $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
125
+ $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
126
+ return false;
127
+ //exit('SetExpressCheckout failed: ' . print_r($httpParsedResponseAr, true));
128
+ }
129
+
130
+ //write session?
131
+
132
+ //redirect to PayPal
133
+ }
134
+
135
+ function getExpressCheckoutDetails(&$order)
136
+ {
137
+ $nvpStr="&TOKEN=".$order->Token;
138
+
139
+ /* Make the API call and store the results in an array. If the
140
+ call was a success, show the authorization details, and provide
141
+ an action to complete the payment. If failed, show the error
142
+ */
143
+ $this->httpParsedResponseAr = $this->PPHttpPost('GetExpressCheckoutDetails', $nvpStr);
144
+
145
+ if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
146
+ $order->status = "review";
147
+
148
+ //update order
149
+ $order->saveOrder();
150
+
151
+ return true;
152
+ } else {
153
+ $order->status = "error";
154
+ $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
155
+ $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
156
+ $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
157
+ return false;
158
+ //exit('SetExpressCheckout failed: ' . print_r($httpParsedResponseAr, true));
159
+ }
160
+ }
161
+
162
+ function charge(&$order)
163
+ {
164
+ global $pmpro_currency;
165
+
166
+ if(empty($order->code))
167
+ $order->code = $order->getRandomCode();
168
+
169
+ //taxes on the amount
170
+ $amount = $order->InitialPayment;
171
+ $amount_tax = $order->getTaxForPrice($amount);
172
+ $order->subtotal = $amount;
173
+ $amount = round((float)$amount + (float)$amount_tax, 2);
174
+
175
+ //paypal profile stuff
176
+ $nvpStr = "";
177
+ if(!empty($order->Token))
178
+ $nvpStr .= "&TOKEN=" . $order->Token;
179
+ $nvpStr .="&AMT=" . $amount . "&CURRENCYCODE=" . $pmpro_currency;
180
+ /*
181
+ if(!empty($amount_tax))
182
+ $nvpStr .= "&TAXAMT=" . $amount_tax;
183
+ */
184
+ if(!empty($order->BillingFrequency))
185
+ $nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLAMT=AddToNextBilling";
186
+ $nvpStr .= "&DESC=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127));
187
+ $nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
188
+ $nvpStr .= "&NOSHIPPING=1";
189
+
190
+ $nvpStr .= "&PAYERID=" . $_SESSION['payer_id'] . "&PAYMENTACTION=sale";
191
+ $order->nvpStr = $nvpStr;
192
+
193
+ $this->httpParsedResponseAr = $this->PPHttpPost('DoExpressCheckoutPayment', $nvpStr);
194
+
195
+ if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
196
+ $order->payment_transaction_id = urldecode($this->httpParsedResponseAr['TRANSACTIONID']);
197
+ $order->status = "success";
198
+
199
+ //update order
200
+ $order->saveOrder();
201
+
202
+ return true;
203
+ } else {
204
+ $order->status = "error";
205
+ $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
206
+ $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
207
+ $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
208
+ return false;
209
+ //exit('SetExpressCheckout failed: ' . print_r($httpParsedResponseAr, true));
210
+ }
211
+ }
212
+
213
+ function subscribe(&$order)
214
+ {
215
+ global $pmpro_currency;
216
+
217
+ if(empty($order->code))
218
+ $order->code = $order->getRandomCode();
219
+
220
+ //filter order before subscription. use with care.
221
+ $order = apply_filters("pmpro_subscribe_order", $order, $this);
222
+
223
+ //taxes on initial amount
224
+ $initial_payment = $order->InitialPayment;
225
+ $initial_payment_tax = $order->getTaxForPrice($initial_payment);
226
+ $initial_payment = round((float)$initial_payment + (float)$initial_payment_tax, 2);
227
+
228
+ //taxes on the amount
229
+ $amount = $order->PaymentAmount;
230
+ $amount_tax = $order->getTaxForPrice($amount);
231
+ //$amount = round((float)$amount + (float)$amount_tax, 2);
232
+
233
+ //paypal profile stuff
234
+ $nvpStr = "";
235
+ if(!empty($order->Token))
236
+ $nvpStr .= "&TOKEN=" . $order->Token;
237
+ $nvpStr .="&INITAMT=" . $initial_payment . "&AMT=" . $amount . "&CURRENCYCODE=" . $pmpro_currency . "&PROFILESTARTDATE=" . $order->ProfileStartDate;
238
+ if(!empty($amount_tax))
239
+ $nvpStr .= "&TAXAMT=" . $amount_tax;
240
+ $nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLAMT=AddToNextBilling";
241
+ $nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
242
+ $nvpStr .= "&DESC=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127));
243
+
244
+ //if billing cycles are defined
245
+ if(!empty($order->TotalBillingCycles))
246
+ $nvpStr .= "&TOTALBILLINGCYCLES=" . $order->TotalBillingCycles;
247
+
248
+ //if a trial period is defined
249
+ if(!empty($order->TrialBillingPeriod))
250
+ {
251
+ $trial_amount = $order->TrialAmount;
252
+ $trial_tax = $order->getTaxForPrice($trial_amount);
253
+ $trial_amount = round((float)$trial_amount + (float)$trial_tax, 2);
254
+
255
+ $nvpStr .= "&TRIALBILLINGPERIOD=" . $order->TrialBillingPeriod . "&TRIALBILLINGFREQUENCY=" . $order->TrialBillingFrequency . "&TRIALAMT=" . $trial_amount;
256
+ }
257
+ if(!empty($order->TrialBillingCycles))
258
+ $nvpStr .= "&TRIALTOTALBILLINGCYCLES=" . $order->TrialBillingCycles;
259
+
260
+ $this->nvpStr = $nvpStr;
261
+
262
+ ///echo str_replace("&", "&<br />", $nvpStr);
263
+ ///exit;
264
+
265
+ $this->httpParsedResponseAr = $this->PPHttpPost('CreateRecurringPaymentsProfile', $nvpStr);
266
+
267
+ if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
268
+ $order->status = "success";
269
+ $order->payment_transaction_id = urldecode($this->httpParsedResponseAr['PROFILEID']);
270
+ $order->subscription_transaction_id = urldecode($this->httpParsedResponseAr['PROFILEID']);
271
+
272
+ //update order
273
+ $order->saveOrder();
274
+
275
+ return true;
276
+ } else {
277
+ $order->status = "error";
278
+ $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
279
+ $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
280
+ $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
281
+
282
+ return false;
283
+ }
284
+ }
285
+
286
+ function cancel(&$order)
287
+ {
288
+ //paypal profile stuff
289
+ $nvpStr = "";
290
+ $nvpStr .= "&PROFILEID=" . urlencode($order->subscription_transaction_id) . "&ACTION=Cancel&NOTE=" . urlencode("User requested cancel.");
291
+
292
+ $this->httpParsedResponseAr = $this->PPHttpPost('ManageRecurringPaymentsProfileStatus', $nvpStr);
293
+
294
+ if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"]))
295
+ {
296
+ $order->updateStatus("cancelled");
297
+ return true;
298
+ }
299
+ else
300
+ {
301
+ $order->status = "error";
302
+ $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
303
+ $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']) . ". " . __("Please contact the site owner or cancel your subscription from within PayPal to make sure you are not charged going forward.", "pmpro");
304
+ $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
305
+
306
+ return false;
307
+ }
308
+ }
309
+
310
+ function getSubscriptionStatus(&$order)
311
+ {
312
+ if(empty($order->subscription_transaction_id))
313
+ return false;
314
+
315
+ //paypal profile stuff
316
+ $nvpStr = "";
317
+ $nvpStr .= "&PROFILEID=" . urlencode($order->subscription_transaction_id);
318
+
319
+ $this->httpParsedResponseAr = $this->PPHttpPost('GetRecurringPaymentsProfileDetails', $nvpStr);
320
+
321
+ if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"]))
322
+ {
323
+ return $this->httpParsedResponseAr;
324
+ }
325
+ else
326
+ {
327
+ $order->status = "error";
328
+ $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
329
+ $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
330
+ $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
331
+
332
+ return false;
333
+ }
334
+ }
335
+
336
+ /**
337
+ * PAYPAL Function
338
+ * Send HTTP POST Request
339
+ *
340
+ * @param string The API method name
341
+ * @param string The POST Message fields in &name=value pair format
342
+ * @return array Parsed HTTP Response body
343
+ */
344
+ function PPHttpPost($methodName_, $nvpStr_) {
345
+ global $gateway_environment;
346
+ $environment = $gateway_environment;
347
+
348
+ $API_UserName = pmpro_getOption("apiusername");
349
+ $API_Password = pmpro_getOption("apipassword");
350
+ $API_Signature = pmpro_getOption("apisignature");
351
+ $API_Endpoint = "https://api-3t.paypal.com/nvp";
352
+ if("sandbox" === $environment || "beta-sandbox" === $environment) {
353
+ $API_Endpoint = "https://api-3t.$environment.paypal.com/nvp";
354
+ }
355
+
356
+ $version = urlencode('72.0');
357
+
358
+ // setting the curl parameters.
359
+ $ch = curl_init();
360
+ curl_setopt($ch, CURLOPT_URL, $API_Endpoint);
361
+ curl_setopt($ch, CURLOPT_VERBOSE, 1);
362
+
363
+ // turning off the server and peer verification(TrustManager Concept).
364
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
365
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
366
+
367
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
368
+ curl_setopt($ch, CURLOPT_POST, 1);
369
+
370
+ // NVPRequest for submitting to server
371
+ $nvpreq = "METHOD=" . urlencode($methodName_) . "&VERSION=" . urlencode($version) . "&PWD=" . urlencode($API_Password) . "&USER=" . urlencode($API_UserName) . "&SIGNATURE=" . urlencode($API_Signature) . $nvpStr_;
372
+
373
+ // setting the nvpreq as POST FIELD to curl
374
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $nvpreq);
375
+
376
+ // getting response from server
377
+ $httpResponse = curl_exec($ch);
378
+
379
+ if(!$httpResponse) {
380
+ exit("$methodName_ failed: ".curl_error($ch).'('.curl_errno($ch).')');
381
+ }
382
+
383
+ // Extract the RefundTransaction response details
384
+ $httpResponseAr = explode("&", $httpResponse);
385
+
386
+ $httpParsedResponseAr = array();
387
+ foreach ($httpResponseAr as $i => $value) {
388
+ $tmpAr = explode("=", $value);
389
+ if(sizeof($tmpAr) > 1) {
390
+ $httpParsedResponseAr[$tmpAr[0]] = $tmpAr[1];
391
+ }
392
+ }
393
+
394
+ if((0 == sizeof($httpParsedResponseAr)) || !array_key_exists('ACK', $httpParsedResponseAr)) {
395
+ exit("Invalid HTTP Response for POST request($nvpreq) to $API_Endpoint.");
396
+ }
397
+
398
+ return $httpParsedResponseAr;
399
+ }
400
+ }
classes/gateways/class.pmprogateway_paypalstandard.php ADDED
@@ -0,0 +1,301 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/class.pmprogateway.php");
3
+ class PMProGateway_paypalstandard
4
+ {
5
+ function PMProGateway_paypalstandard($gateway = NULL)
6
+ {
7
+ $this->gateway = $gateway;
8
+ return $this->gateway;
9
+ }
10
+
11
+ function process(&$order)
12
+ {
13
+ if(empty($order->code))
14
+ $order->code = $order->getRandomCode();
15
+
16
+ //clean up a couple values
17
+ $order->payment_type = "PayPal Standard";
18
+ $order->CardType = "";
19
+ $order->cardtype = "";
20
+
21
+ //just save, the user will go to PayPal to pay
22
+ $order->status = "review";
23
+ $order->saveOrder();
24
+
25
+ return true;
26
+ }
27
+
28
+ function sendToPayPal(&$order)
29
+ {
30
+ global $pmpro_currency;
31
+
32
+ //taxes on initial amount
33
+ $initial_payment = $order->InitialPayment;
34
+ $initial_payment_tax = $order->getTaxForPrice($initial_payment);
35
+ $initial_payment = round((float)$initial_payment + (float)$initial_payment_tax, 2);
36
+
37
+ //taxes on the amount
38
+ $amount = $order->PaymentAmount;
39
+ $amount_tax = $order->getTaxForPrice($amount);
40
+ $amount = round((float)$amount + (float)$amount_tax, 2);
41
+
42
+ //build PayPal Redirect
43
+ $environment = pmpro_getOption("gateway_environment");
44
+ if("sandbox" === $environment || "beta-sandbox" === $environment)
45
+ $paypal_url ="https://www.sandbox.paypal.com/cgi-bin/webscr?business=" . urlencode(pmpro_getOption("gateway_email"));
46
+ else
47
+ $paypal_url = "https://www.paypal.com/cgi-bin/webscr?business=" . urlencode(pmpro_getOption("gateway_email"));
48
+
49
+ if(pmpro_isLevelRecurring($order->membership_level))
50
+ {
51
+ //convert billing period
52
+ if($order->BillingPeriod == "Day")
53
+ $period = "D";
54
+ elseif($order->BillingPeriod == "Week")
55
+ $period = "W";
56
+ elseif($order->BillingPeriod == "Month")
57
+ $period = "M";
58
+ elseif($order->BillingPeriod == "Year")
59
+ $period = "Y";
60
+ else
61
+ {
62
+ $order->error = "Invalid billing period: " . $order->BillingPeriod;
63
+ $order->shorterror = "Invalid billing period: " . $order->BillingPeriod;
64
+ return false;
65
+ }
66
+
67
+ //other args
68
+ $paypal_args = array(
69
+ 'cmd' => '_xclick-subscriptions',
70
+ 'a1' => number_format($initial_payment, 2),
71
+ 'p1' => $order->BillingFrequency,
72
+ 't1' => $period,
73
+ 'a3' => number_format($amount, 2),
74
+ 'p3' => $order->BillingFrequency,
75
+ 't3' => $period,
76
+ 'item_name' => substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127),
77
+ 'email' => $order->Email,
78
+ 'no_shipping' => '1',
79
+ 'shipping' => '0',
80
+ 'no_note' => '1',
81
+ 'currency_code' => $pmpro_currency,
82
+ 'item_number' => $order->code,
83
+ 'charset' => get_bloginfo( 'charset' ),
84
+ 'rm' => '2',
85
+ 'return' => pmpro_url("confirmation", "?level=" . $order->membership_level->id),
86
+ 'notify_url' => admin_url("admin-ajax.php") . "?action=ipnhandler",
87
+ 'src' => '1',
88
+ 'sra' => '1'
89
+ );
90
+
91
+ //trial?
92
+ /*
93
+ Note here that the TrialBillingCycles value is being ignored. PayPal Standard only offers 1 payment during each trial period.
94
+ */
95
+ if(!empty($order->TrialBillingPeriod))
96
+ {
97
+ //if a1 and a2 are 0, let's just combine them. PayPal doesn't like a2 = 0.
98
+ if($paypal_args['a1'] == 0 && $order->TrialAmount == 0)
99
+ {
100
+ $paypal_args['p1'] = $paypal_args['p1'] + $order->TrialBillingFrequency;
101
+ }
102
+ else
103
+ {
104
+ $trial_amount = $order->TrialAmount;
105
+ $trial_tax = $order->getTaxForPrice($trial_amount);
106
+ $trial_amount = round((float)$trial_amount + (float)$trial_tax, 2);
107
+
108
+ $paypal_args['a2'] = $trial_amount;
109
+ $paypal_args['p2'] = $order->TrialBillingFrequency;
110
+ $paypal_args['t2'] = $period;
111
+ }
112
+ }
113
+ else
114
+ {
115
+ //we can try to work in any change in ProfileStartDate
116
+ $psd = date("Y-m-d", strtotime("+ " . $order->BillingFrequency . " " . $order->BillingPeriod, current_time("timestamp"))) . "T0:0:0";
117
+ $adjusted_psd = apply_filters("pmpro_profile_start_date", $psd, $order);
118
+ if($psd != $adjusted_psd)
119
+ {
120
+ //someone is trying to push the start date back
121
+ $adjusted_psd_time = strtotime($adjusted_psd, current_time("timestamp"));
122
+ $seconds_til_psd = $adjusted_psd_time - current_time('timestamp');
123
+ $days_til_psd = floor($seconds_til_psd/(60*60*24));
124
+
125
+ //push back trial one by days_til_psd
126
+ if($days_til_psd > 90)
127
+ {
128
+ //we need to convert to weeks, because PayPal limits t1 to 90 days
129
+ $weeks_til_psd = round($days_til_psd / 7);
130
+ $paypal_args['p1'] = $weeks_til_psd;
131
+ $paypal_args['t1'] = "W";
132
+ }
133
+ elseif($days_til_psd > 0)
134
+ {
135
+ //use days
136
+ $paypal_args['p1'] = $days_til_psd;
137
+ $paypal_args['t1'] = "D";
138
+ }
139
+ }
140
+ }
141
+
142
+ //billing limit?
143
+ if(!empty($order->TotalBillingCycles))
144
+ {
145
+ if(!empty($trial_amount))
146
+ {
147
+
148
+ $srt = intval($order->TotalBillingCycles) - 1; //subtract one for the trial period
149
+ }
150
+ else
151
+ {
152
+ $srt = intval($order->TotalBillingCycles);
153
+ }
154
+
155
+ //srt must be at least 2 or the subscription is not "recurring" according to paypal
156
+ if($srt > 1)
157
+ $paypal_args['srt'] = $srt;
158
+ else
159
+ $paypal_args['src'] = '0';
160
+ }
161
+ else
162
+ $paypal_args['srt'] = '0'; //indefinite subscription
163
+ }
164
+ else
165
+ {
166
+ //other args
167
+ $paypal_args = array(
168
+ 'cmd' => '_xclick',
169
+ 'amount' => number_format($initial_payment, 2),
170
+ 'item_name' => substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127),
171
+ 'email' => $order->Email,
172
+ 'no_shipping' => '1',
173
+ 'shipping' => '0',
174
+ 'no_note' => '1',
175
+ 'currency_code' => $pmpro_currency,
176
+ 'item_number' => $order->code,
177
+ 'charset' => get_bloginfo( 'charset' ),
178
+ 'rm' => '2',
179
+ 'return' => pmpro_url("confirmation", "?level=" . $order->membership_level->id),
180
+ 'notify_url' => admin_url("admin-ajax.php") . "?action=ipnhandler"
181
+ );
182
+ }
183
+
184
+ $nvpStr = "";
185
+ foreach($paypal_args as $key => $value)
186
+ {
187
+ $nvpStr .= "&" . $key . "=" . urlencode($value);
188
+ }
189
+
190
+ //anything modders might add
191
+ $additional_parameters = apply_filters("pmpro_paypal_express_return_url_parameters", array());
192
+ if(!empty($additional_parameters))
193
+ {
194
+ foreach($additional_parameters as $key => $value)
195
+ $nvpStr .= urlencode("&" . $key . "=" . $value);
196
+ }
197
+
198
+ $account_optional = apply_filters('pmpro_paypal_account_optional', true);
199
+ if ($account_optional)
200
+ $nvpStr .= '&SOLUTIONTYPE=Sole&LANDINGPAGE=Billing';
201
+
202
+ $nvpStr = apply_filters("pmpro_paypal_standard_nvpstr", $nvpStr, $order);
203
+
204
+ //redirect to paypal
205
+ $paypal_url .= $nvpStr;
206
+
207
+ //wp_die(str_replace("&", "<br />", $paypal_url));
208
+
209
+ wp_redirect($paypal_url);
210
+ exit;
211
+ }
212
+
213
+ function cancel(&$order)
214
+ {
215
+ //paypal profile stuff
216
+ $nvpStr = "";
217
+ $nvpStr .= "&PROFILEID=" . urlencode($order->subscription_transaction_id) . "&ACTION=Cancel&NOTE=" . urlencode("User requested cancel.");
218
+
219
+ $this->httpParsedResponseAr = $this->PPHttpPost('ManageRecurringPaymentsProfileStatus', $nvpStr);
220
+
221
+ if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"]))
222
+ {
223
+ $order->updateStatus("cancelled");
224
+ return true;
225
+ }
226
+ else
227
+ {
228
+ $order->status = "error";
229
+ $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
230
+ $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']) . ". " . __("Please contact the site owner or cancel your subscription from within PayPal to make sure you are not charged going forward.", "pmpro");
231
+ $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
232
+
233
+ return false;
234
+ }
235
+ }
236
+
237
+ /**
238
+ * PAYPAL Function
239
+ * Send HTTP POST Request
240
+ *
241
+ * @param string The API method name
242
+ * @param string The POST Message fields in &name=value pair format
243
+ * @return array Parsed HTTP Response body
244
+ */
245
+ function PPHttpPost($methodName_, $nvpStr_) {
246
+ global $gateway_environment;
247
+ $environment = $gateway_environment;
248
+
249
+ $API_UserName = pmpro_getOption("apiusername");
250
+ $API_Password = pmpro_getOption("apipassword");
251
+ $API_Signature = pmpro_getOption("apisignature");
252
+ $API_Endpoint = "https://api-3t.paypal.com/nvp";
253
+ if("sandbox" === $environment || "beta-sandbox" === $environment) {
254
+ $API_Endpoint = "https://api-3t.$environment.paypal.com/nvp";
255
+ }
256
+
257
+ $version = urlencode('72.0');
258
+
259
+ // setting the curl parameters.
260
+ $ch = curl_init();
261
+ curl_setopt($ch, CURLOPT_URL, $API_Endpoint);
262
+ curl_setopt($ch, CURLOPT_VERBOSE, 1);
263
+
264
+ // turning off the server and peer verification(TrustManager Concept).
265
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
266
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
267
+
268
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
269
+ curl_setopt($ch, CURLOPT_POST, 1);
270
+
271
+ // NVPRequest for submitting to server
272
+ $nvpreq = "METHOD=" . urlencode($methodName_) . "&VERSION=" . urlencode($version) . "&PWD=" . urlencode($API_Password) . "&USER=" . urlencode($API_UserName) . "&SIGNATURE=" . urlencode($API_Signature) . $nvpStr_;
273
+
274
+ // setting the nvpreq as POST FIELD to curl
275
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $nvpreq);
276
+
277
+ // getting response from server
278
+ $httpResponse = curl_exec($ch);
279
+
280
+ if(!$httpResponse) {
281
+ exit("$methodName_ failed: ".curl_error($ch).'('.curl_errno($ch).')');
282
+ }
283
+
284
+ // Extract the RefundTransaction response details
285
+ $httpResponseAr = explode("&", $httpResponse);
286
+
287
+ $httpParsedResponseAr = array();
288
+ foreach ($httpResponseAr as $i => $value) {
289
+ $tmpAr = explode("=", $value);
290
+ if(sizeof($tmpAr) > 1) {
291
+ $httpParsedResponseAr[$tmpAr[0]] = $tmpAr[1];
292
+ }
293
+ }
294
+
295
+ if((0 == sizeof($httpParsedResponseAr)) || !array_key_exists('ACK', $httpParsedResponseAr)) {
296
+ exit("Invalid HTTP Response for POST request($nvpreq) to $API_Endpoint.");
297
+ }
298
+
299
+ return $httpParsedResponseAr;
300
+ }
301
+ }
classes/gateways/class.pmprogateway_stripe.php ADDED
@@ -0,0 +1,428 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/class.pmprogateway.php");
3
+ if(!class_exists("Stripe"))
4
+ require_once(dirname(__FILE__) . "/../../includes/lib/Stripe/Stripe.php");
5
+ class PMProGateway_stripe
6
+ {
7
+ function PMProGateway_stripe($gateway = NULL)
8
+ {
9
+ $this->gateway = $gateway;
10
+ $this->gateway_environment = pmpro_getOption("gateway_environment");
11
+
12
+ Stripe::setApiKey(pmpro_getOption("stripe_secretkey"));
13
+
14
+ return $this->gateway;
15
+ }
16
+
17
+ function process(&$order)
18
+ {
19
+ //check for initial payment
20
+ if(floatval($order->InitialPayment) == 0)
21
+ {
22
+ //just subscribe
23
+ return $this->subscribe($order);
24
+ }
25
+ else
26
+ {
27
+ //charge then subscribe
28
+ if($this->charge($order))
29
+ {
30
+ if(pmpro_isLevelRecurring($order->membership_level))
31
+ {
32
+ if($this->subscribe($order))
33
+ {
34
+ //yay!
35
+ return true;
36
+ }
37
+ else
38
+ {
39
+ //try to refund initial charge
40
+ return false;
41
+ }
42
+ }
43
+ else
44
+ {
45
+ //only a one time charge
46
+ $order->status = "success"; //saved on checkout page
47
+ return true;
48
+ }
49
+ }
50
+ else
51
+ {
52
+ if(empty($order->error))
53
+ $order->error = __("Unknown error: Initial payment failed.", "pmpro");
54
+ return false;
55
+ }
56
+ }
57
+ }
58
+
59
+ function charge(&$order)
60
+ {
61
+ global $pmpro_currency;
62
+
63
+ //create a code for the order
64
+ if(empty($order->code))
65
+ $order->code = $order->getRandomCode();
66
+
67
+ //what amount to charge?
68
+ $amount = $order->InitialPayment;
69
+
70
+ //tax
71
+ $order->subtotal = $amount;
72
+ $tax = $order->getTax(true);
73
+ $amount = round((float)$order->subtotal + (float)$tax, 2);
74
+
75
+ //create a customer
76
+ $this->getCustomer($order);
77
+ if(empty($this->customer))
78
+ {
79
+ //failed to create customer
80
+ return false;
81
+ }
82
+
83
+ //charge
84
+ try
85
+ {
86
+ $response = Stripe_Charge::create(array(
87
+ "amount" => $amount * 100, # amount in cents, again
88
+ "currency" => $pmpro_currency,
89
+ "customer" => $this->customer->id,
90
+ "description" => "Order #" . $order->code . ", " . trim($order->FirstName . " " . $order->LastName) . " (" . $order->Email . ")"
91
+ )
92
+ );
93
+ }
94
+ catch (Exception $e)
95
+ {
96
+ //$order->status = "error";
97
+ $order->errorcode = true;
98
+ $order->error = "Error: " . $e->getMessage();
99
+ $order->shorterror = $order->error;
100
+ return false;
101
+ }
102
+
103
+ if(empty($response["failure_message"]))
104
+ {
105
+ //successful charge
106
+ $order->payment_transaction_id = $response["id"];
107
+ $order->updateStatus("success");
108
+ return true;
109
+ }
110
+ else
111
+ {
112
+ //$order->status = "error";
113
+ $order->errorcode = true;
114
+ $order->error = $response['failure_message'];
115
+ $order->shorterror = $response['failure_message'];
116
+ return false;
117
+ }
118
+ }
119
+
120
+ /*
121
+ This function will return a Stripe customer object.
122
+ If $this->customer is set, it returns it.
123
+ It first checks if the order has a subscription_transaction_id. If so, that's the customer id.
124
+ If not, it checks for a user_id on the order and searches for a customer id in the user meta.
125
+ If a customer id is found, it checks for a customer through the Stripe API.
126
+ If a customer is found and there is a stripeToken on the order passed, it will update the customer.
127
+ If no customer is found and there is a stripeToken on the order passed, it will create a customer.
128
+ */
129
+ function getCustomer(&$order, $force = false)
130
+ {
131
+ global $current_user;
132
+
133
+ //already have it?
134
+ if(!empty($this->customer) && !$force)
135
+ return $this->customer;
136
+
137
+ //transaction id?
138
+ if(!empty($order->subscription_transaction_id))
139
+ $customer_id = $order->subscription_transaction_id;
140
+ else
141
+ {
142
+ //try based on user id
143
+ if(!empty($order->user_id))
144
+ $user_id = $order->user_id;
145
+
146
+ //if no id passed, check the current user
147
+ if(empty($user_id) && !empty($current_user->ID))
148
+ $user_id = $current_user->ID;
149
+
150
+ //check for a stripe customer id
151
+ if(!empty($user_id))
152
+ {
153
+ $customer_id = get_user_meta($user_id, "pmpro_stripe_customerid", true);
154
+ }
155
+ }
156
+
157
+ //check for an existing stripe customer
158
+ if(!empty($customer_id))
159
+ {
160
+ try
161
+ {
162
+ $this->customer = Stripe_Customer::retrieve($customer_id);
163
+
164
+ //update the customer description and card
165
+ if(!empty($order->stripeToken))
166
+ {
167
+ $name = trim($order->FirstName . " " . $order->LastName);
168
+
169
+ if (empty($name))
170
+ {
171
+ $name = trim($current_user->first_name . " " . $current_user->last_name);
172
+ }
173
+
174
+ $this->customer->description = $name . " (" . $order->Email . ")";
175
+ $this->customer->email = $order->Email;
176
+ $this->customer->card = $order->stripeToken;
177
+ $this->customer->save();
178
+ }
179
+
180
+ return $this->customer;
181
+ }
182
+ catch (Exception $e)
183
+ {
184
+ //assume no customer found
185
+ }
186
+ }
187
+
188
+ //no customer id, create one
189
+ if(!empty($order->stripeToken))
190
+ {
191
+ try
192
+ {
193
+ $this->customer = Stripe_Customer::create(array(
194
+ "description" => trim($order->FirstName . " " . $order->LastName) . " (" . $order->Email . ")",
195
+ "email" => $order->Email,
196
+ "card" => $order->stripeToken
197
+ ));
198
+ }
199
+ catch (Exception $e)
200
+ {
201
+ $order->error = __("Error creating customer record with Stripe:", "pmpro") . " " . $e->getMessage();
202
+ $order->shorterror = $order->error;
203
+ return false;
204
+ }
205
+
206
+ if(!empty($user_id))
207
+ {
208
+ //user logged in/etc
209
+ update_user_meta($user_id, "pmpro_stripe_customerid", $this->customer->id);
210
+ }
211
+ else
212
+ {
213
+ //user not registered yet, queue it up
214
+ global $pmpro_stripe_customer_id;
215
+ $pmpro_stripe_customer_id = $this->customer->id;
216
+ function pmpro_user_register_stripe_customerid($user_id)
217
+ {
218
+ global $pmpro_stripe_customer_id;
219
+ update_user_meta($user_id, "pmpro_stripe_customerid", $pmpro_stripe_customer_id);
220
+ }
221
+ add_action("user_register", "pmpro_user_register_stripe_customerid");
222
+ }
223
+
224
+ return apply_filters('pmpro_stripe_create_customer', $this->customer);
225
+ }
226
+
227
+ return false;
228
+ }
229
+
230
+ function subscribe(&$order)
231
+ {
232
+ global $pmpro_currency;
233
+
234
+ //create a code for the order
235
+ if(empty($order->code))
236
+ $order->code = $order->getRandomCode();
237
+
238
+ //filter order before subscription. use with care.
239
+ $order = apply_filters("pmpro_subscribe_order", $order, $this);
240
+
241
+ //setup customer
242
+ $this->getCustomer($order);
243
+ if(empty($this->customer))
244
+ return false; //error retrieving customer
245
+
246
+ //set subscription id to custom id
247
+ $order->subscription_transaction_id = $this->customer['id']; //transaction id is the customer id, we save it in user meta later too
248
+
249
+ //figure out the amounts
250
+ $amount = $order->PaymentAmount;
251
+ $amount_tax = $order->getTaxForPrice($amount);
252
+ $amount = round((float)$amount + (float)$amount_tax, 2);
253
+
254
+ /*
255
+ There are two parts to the trial. Part 1 is simply the delay until the first payment
256
+ since we are doing the first payment as a separate transaction.
257
+ The second part is the actual "trial" set by the admin.
258
+
259
+ Stripe only supports Year or Month for billing periods, but we account for Days and Weeks just in case.
260
+ */
261
+ //figure out the trial length (first payment handled by initial charge)
262
+ if($order->BillingPeriod == "Year")
263
+ $trial_period_days = $order->BillingFrequency * 365; //annual
264
+ elseif($order->BillingPeriod == "Day")
265
+ $trial_period_days = $order->BillingFrequency * 1; //daily
266
+ elseif($order->BillingPeriod == "Week")
267
+ $trial_period_days = $order->BillingFrequency * 7; //weekly
268
+ else
269
+ $trial_period_days = $order->BillingFrequency * 30; //assume monthly
270
+
271
+ //convert to a profile start date
272
+ $order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $trial_period_days . " Day", current_time("timestamp"))) . "T0:0:0";
273
+
274
+ //filter the start date
275
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
276
+
277
+ //convert back to days
278
+ $trial_period_days = ceil(abs(strtotime(date("Y-m-d"), current_time("timestamp")) - strtotime($order->ProfileStartDate, current_time("timestamp"))) / 86400);
279
+
280
+ //now add the actual trial set by the site
281
+ if(!empty($order->TrialBillingCycles))
282
+ {
283
+ $trialOccurrences = (int)$order->TrialBillingCycles;
284
+ if($order->BillingPeriod == "Year")
285
+ $trial_period_days = $trial_period_days + (365 * $order->BillingFrequency * $trialOccurrences); //annual
286
+ elseif($order->BillingPeriod == "Day")
287
+ $trial_period_days = $trial_period_days + (1 * $order->BillingFrequency * $trialOccurrences); //daily
288
+ elseif($order->BillingPeriod == "Week")
289
+ $trial_period_days = $trial_period_days + (7 * $order->BillingFrequency * $trialOccurrences); //weekly
290
+ else
291
+ $trial_period_days = $trial_period_days + (30 * $order->BillingFrequency * $trialOccurrences); //assume monthly
292
+ }
293
+
294
+ //create a plan
295
+ try
296
+ {
297
+ $plan = array(
298
+ "amount" => $amount * 100,
299
+ "interval_count" => $order->BillingFrequency,
300
+ "interval" => strtolower($order->BillingPeriod),
301
+ "trial_period_days" => $trial_period_days,
302
+ "name" => $order->membership_name . " for order " . $order->code,
303
+ "currency" => strtolower($pmpro_currency),
304
+ "id" => $order->code
305
+ );
306
+
307
+ $plan = Stripe_Plan::create(apply_filters('pmpro_stripe_create_plan_array', $plan));
308
+ }
309
+ catch (Exception $e)
310
+ {
311
+ $order->error = __("Error creating plan with Stripe:", "pmpro") . $e->getMessage();
312
+ $order->shorterror = $order->error;
313
+ return false;
314
+ }
315
+
316
+ if(empty($order->subscription_transaction_id) && !empty($this->customer['id']))
317
+ $order->subscription_transaction_id = $this->customer['id'];
318
+
319
+ //subscribe to the plan
320
+ try
321
+ {
322
+ $this->customer->subscriptions->create(array("plan" => $order->code));
323
+ }
324
+ catch (Exception $e)
325
+ {
326
+ //try to delete the plan
327
+ $plan->delete();
328
+
329
+ //return error
330
+ $order->error = __("Error subscribing customer to plan with Stripe:", "pmpro") . $e->getMessage();
331
+ $order->shorterror = $order->error;
332
+ return false;
333
+ }
334
+
335
+ //delete the plan
336
+ $plan = Stripe_Plan::retrieve($order->code);
337
+ $plan->delete();
338
+
339
+ //if we got this far, we're all good
340
+ $order->status = "success";
341
+ return true;
342
+ }
343
+
344
+ function update(&$order)
345
+ {
346
+ //we just have to run getCustomer which will look for the customer and update it with the new token
347
+ $this->getCustomer($order);
348
+
349
+ if(!empty($this->customer))
350
+ {
351
+ return true;
352
+ }
353
+ else
354
+ {
355
+ return false; //couldn't find the customer
356
+ }
357
+ }
358
+
359
+ function cancel(&$order, $update_status = true)
360
+ {
361
+ //no matter what happens below, we're going to cancel the order in our system
362
+ if($update_status)
363
+ $order->updateStatus("cancelled");
364
+
365
+ //require a subscription id
366
+ if(empty($order->subscription_transaction_id))
367
+ return false;
368
+
369
+ //find the customer
370
+ $this->getCustomer($order);
371
+
372
+ if(!empty($this->customer))
373
+ {
374
+ //find subscription with this order code
375
+ $subscriptions = $this->customer->subscriptions->all();
376
+
377
+ //get open invoices
378
+ $invoices = $this->customer->invoices();
379
+ $invoices = $invoices->all();
380
+
381
+ if(!empty($subscriptions))
382
+ {
383
+ foreach($subscriptions->data as $sub)
384
+ {
385
+ if($sub->plan->id == $order->code)
386
+ {
387
+ //found it, cancel it
388
+ try
389
+ {
390
+ //find any open invoices for this subscription and forgive them
391
+ if(!empty($invoices))
392
+ {
393
+ foreach($invoices->data as $invoice)
394
+ {
395
+ if(!$invoice->closed && $invoice->subscription == $sub->id)
396
+ {
397
+ $invoice->closed = true;
398
+ $invoice->save();
399
+ }
400
+ }
401
+ }
402
+
403
+ //cancel
404
+ $r = $sub->cancel();
405
+
406
+ break;
407
+ }
408
+ catch(Exception $e)
409
+ {
410
+ $order->error = __("Could not cancel old subscription.", "pmpro");
411
+ $order->shorterror = $order->error;
412
+
413
+ return false;
414
+ }
415
+ }
416
+ }
417
+ }
418
+
419
+ return true;
420
+ }
421
+ else
422
+ {
423
+ $order->error = __("Could not find the subscription.", "pmpro");
424
+ $order->shorterror = $order->error;
425
+ return false; //no customer found
426
+ }
427
+ }
428
+ }
classes/gateways/class.pmprogateway_twocheckout.php ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/class.pmprogateway.php");
3
+ if(!class_exists("Twocheckout"))
4
+ require_once(dirname(__FILE__) . "/../../includes/lib/Twocheckout/Twocheckout.php");
5
+ class PMProGateway_Twocheckout
6
+ {
7
+ function PMProGateway_Twocheckout($gateway = NULL)
8
+ {
9
+ $this->gateway = $gateway;
10
+ return $this->gateway;
11
+ }
12
+
13
+ function process(&$order)
14
+ {
15
+ if(empty($order->code))
16
+ $order->code = $order->getRandomCode();
17
+
18
+ //clean up a couple values
19
+ $order->payment_type = "2CheckOut";
20
+ $order->CardType = "";
21
+ $order->cardtype = "";
22
+
23
+ //just save, the user will go to 2checkout to pay
24
+ $order->status = "review";
25
+ $order->saveOrder();
26
+
27
+ return true;
28
+ }
29
+
30
+ function sendToTwocheckout(&$order)
31
+ {
32
+ global $pmpro_currency;
33
+ // Set up credentials
34
+ Twocheckout::setCredentials( pmpro_getOption("twocheckout_apiusername"), pmpro_getOption("twocheckout_apipassword") );
35
+
36
+ $tco_args = array(
37
+ 'sid' => pmpro_getOption("twocheckout_accountnumber"),
38
+ 'mode' => '2CO', // will always be 2CO according to docs (@see https://www.2checkout.com/documentation/checkout/parameter-sets/pass-through-products/)
39
+ 'li_0_type' => 'product',
40
+ 'li_0_name' => substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127),
41
+ 'li_0_quantity' => 1,
42
+ 'li_0_tangible' => 'N',
43
+ 'li_0_product_id' => $order->code,
44
+ 'merchant_order_id' => $order->code,
45
+ 'currency_code' => $pmpro_currency,
46
+ 'pay_method' => 'CC',
47
+ 'purchase_step' => 'billing-information',
48
+ 'x_receipt_link_url' => admin_url("admin-ajax.php") . "?action=twocheckout-ins" //pmpro_url("confirmation", "?level=" . $order->membership_level->id)
49
+ );
50
+
51
+ //taxes on initial amount
52
+ $initial_payment = $order->InitialPayment;
53
+ $initial_payment_tax = $order->getTaxForPrice($initial_payment);
54
+ $initial_payment = round((float)$initial_payment + (float)$initial_payment_tax, 2);
55
+
56
+ //taxes on the amount (NOT CURRENTLY USED)
57
+ $amount = $order->PaymentAmount;
58
+ $amount_tax = $order->getTaxForPrice($amount);
59
+ $amount = round((float)$amount + (float)$amount_tax, 2);
60
+
61
+ // Recurring membership
62
+ if( pmpro_isLevelRecurring( $order->membership_level ) ) {
63
+ $tco_args['li_0_startup_fee'] = number_format($initial_payment - $amount, 2); //negative amount for lower initial payments
64
+ $recurring_payment = $order->membership_level->billing_amount;
65
+ $recurring_payment_tax = $order->getTaxForPrice($recurring_payment);
66
+ $recurring_payment = round((float)$recurring_payment + (float)$recurring_payment_tax, 2);
67
+ $tco_args['li_0_price'] = number_format($recurring_payment, 2);
68
+
69
+ $tco_args['li_0_recurrence'] = ( $order->BillingFrequency == 1 ) ? $order->BillingFrequency . ' ' . $order->BillingPeriod : $order->BillingFrequency . ' ' . $order->BillingPeriod . 's';
70
+
71
+ if( property_exists( $order, 'TotalBillingCycles' ) )
72
+ $tco_args['li_0_duration'] = ($order->BillingFrequency * $order->TotalBillingCycles ) . ' ' . $order->BillingPeriod;
73
+ else
74
+ $tco_args['li_0_duration'] = 'Forever';
75
+ }
76
+ // Non-recurring membership
77
+ else {
78
+ $tco_args['li_0_price'] = $initial_payment;
79
+ }
80
+
81
+ // Demo mode?
82
+ $environment = pmpro_getOption("gateway_environment");
83
+ if("sandbox" === $environment || "beta-sandbox" === $environment)
84
+ $tco_args['demo'] = 'Y';
85
+
86
+ // Trial?
87
+ //li_#_startup_fee Any start up fees for the product or service. Can be negative to provide discounted first installment pricing, but cannot equal or surpass the product price.
88
+ if(!empty($order->TrialBillingPeriod)) {
89
+ $trial_amount = $order->TrialAmount;
90
+ $trial_tax = $order->getTaxForPrice($trial_amount);
91
+ $trial_amount = round((float)$trial_amount + (float)$trial_tax, 2);
92
+ $tco_args['li_0_startup_fee'] = $trial_amount; // Negative trial amount
93
+ }
94
+
95
+ $ptpStr = '';
96
+ foreach( $tco_args as $key => $value ) {
97
+ reset( $tco_args ); // Used to verify whether or not we're on the first argument
98
+ $ptpStr .= ( $key == key($tco_args) ) ? '?' . $key . '=' . urlencode( $value ) : '&' . $key . '=' . urlencode( $value );
99
+ }
100
+
101
+ //anything modders might add
102
+ $additional_parameters = apply_filters( 'pmpro_twocheckout_return_url_parameters', array() );
103
+ if( ! empty( $additional_parameters ) )
104
+ foreach( $additional_parameters as $key => $value )
105
+ $ptpStr .= "&" . urlencode($key) . "=" . urlencode($value);
106
+
107
+ $ptpStr = apply_filters( 'pmpro_twocheckout_ptpstr', $ptpStr, $order );
108
+
109
+ //echo str_replace("&", "&<br />", $ptpStr);
110
+ //exit;
111
+
112
+ //redirect to 2checkout
113
+ $tco_url = 'https://www.2checkout.com/checkout/purchase' . $ptpStr;
114
+
115
+ //echo $tco_url;
116
+ //die();
117
+ wp_redirect( $tco_url );
118
+ exit;
119
+ }
120
+
121
+ function cancel(&$order) {
122
+ // If recurring, stop the recurring payment
123
+ if(pmpro_isLevelRecurring($order->membership_level)) {
124
+ $params['sale_id'] = $order->payment_transaction_id;
125
+ $result = Twocheckout_Sale::stop( $params ); // Stop the recurring billing
126
+
127
+ // Successfully cancelled
128
+ if (isset($result['response_code']) && $result['response_code'] === 'OK') {
129
+ $order->updateStatus("cancelled");
130
+ return true;
131
+ }
132
+ // Failed
133
+ else {
134
+ $order->status = "error";
135
+ $order->errorcode = $result->getCode();
136
+ $order->error = $result->getMessage();
137
+
138
+ return false;
139
+ }
140
+ }
141
+
142
+ return $order;
143
+ }
144
+ }
css/admin-rtl.css ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .pmpro_admin {
2
+ background: url(../images/Paid-Memberships-Pro_watermark.png) bottom left no-repeat !important;
3
+ }
4
+
5
+ .pmpro_admin .pmpro_banner h2 {
6
+ float: right;
7
+ }
8
+
9
+ .pmpro_admin .pmpro_banner .pmpro_meta {
10
+ float: right;
11
+ }
12
+
13
+ .pmpro_admin .pmpro_banner .pmpro_meta .pmpro_tag-blue {
14
+ margin: 0 5px 0 0;
15
+ }
16
+
17
+ .pmpro_admin .pmpro_banner .pmpro_logo {
18
+ float: right;
19
+ margin: 0 0 0 1em;
20
+ }
21
+
22
+ .pmpro_admin .pmpro_banner ul.pmpro_menu li {
23
+ border-left: 1px solid #CCC;
24
+ border-right: none;
25
+ }
26
+
27
+ /* messages */
28
+ .pmpro_message {
29
+ padding: 6px 25px 6px 6px;
30
+ }
31
+
32
+ /* highlighted trs */
33
+
34
+ /* discount levels */
35
+
36
+ /* pagination */
37
+ div.pmpro_pagination {
38
+ float: left;
39
+ }
40
+
41
+ /* add ons */
42
+
43
+ .pmpro_admin .widgets-holder-wrap .widget {
44
+ float: right;
45
+ margin: 0 0 1% 1%;
46
+ }
47
+
48
+ .pmpro_admin .widgets-holder-wrap .widget-title .status-label {
49
+ float: right;
50
+ margin: 0 0 0 5px;
51
+ }
52
+
53
+ .pmpro_admin .widgets-holder-wrap .widget-title .version {
54
+ left: 10px;
55
+ left: auto;
56
+ }
57
+
58
+ .pmpro_admin .widgets-holder-wrap .widget-inside .addon-thumb {
59
+ float: left;
60
+ margin: 10px 10px 0 0;
61
+ }
62
+
63
+ /* Generated by the RTLer - http://l0uy.com/rtler/ */
css/admin.css CHANGED
@@ -1,43 +1,97 @@
1
- .pmpro_admin {background: url(../images/PaidMembershipsPro-grey.gif) bottom right no-repeat !important; padding-bottom: 70px; }
2
-
3
- .pmpro_admin .pmpro_banner {margin: 2em 0; font-family: Georgia, "Times New Roman", Times, serif; }
4
- .pmpro_admin .pmpro_banner .pmpro_meta {float: right; margin: 2em 0 1em 1em; font-size: 12px; font-style: italic; }
5
- .pmpro_admin .pmpro_banner .pmpro_logo {float: left; margin: 0 1em 1em 0; width: 350px; }
6
- .pmpro_admin .pmpro_banner .pmpro_tagline {float: left; width: 350px; font-family: "Arial Black", Gadget, sans-serif; color: #412f5b; text-transform: uppercase; font-size: 13px; padding: 15px 0; }
7
- .pmpro_admin .pmpro_banner ul.pmpro_menu {clear: both; border: 1px solid #CCC; border-radius: 5px; -moz-border-radius: 5px; background: #FFF; }
8
- .pmpro_admin .pmpro_banner ul.pmpro_menu li {display: inline-block; margin: 10px 0; padding: 0px 10px; border-right: 1px solid #CCC; }
9
- .pmpro_admin .pmpro_banner ul.pmpro_menu li a, .pmpro_admin .pmpro_banner ul.pmpro_menu li a:link {color: #1e0741; text-decoration: none; }
10
- .pmpro_admin .pmpro_banner ul.pmpro_menu li a:hover {text-decoration: underline; color: #412f5b; }
11
-
12
- .pmpro_admin .topborder {border-top: 1px solid #CCC; margin-top: 1em; padding-top: 1em; }
13
- .pmpro_admin #editorcontainer #description {width: 100%; height: 180px; }
14
- .pmpro_admin .widefat {margin-top: 1em; }
15
-
16
- .ssp_description #description {width: 100%;}
17
- .checkbox_box {width: 300px; background: #FFFFFF; border: 1px solid #CCC;}
18
- .checkbox_box div {border-bottom: 1px solid #CCC; padding: 3px;}
19
- .checkbox_box .clickable {cursor: pointer;}
20
- .checkbox_box .clickable:hover {background: #FFC;}
21
- .top0em {margin-top: 0;}
22
-
23
- tr.pmpro_gray td {color: #AAA;}
24
-
25
- .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; }
26
-
27
- .pmpro_success {background-color: #CFEECA; background-image: url(../images/icon_success.gif); color: #208A1B; }
28
- .pmpro_error {background-color: #F9D6CB; background-image: url(../images/icon_error.gif); color: #E36154; }
29
- .pmpro_alert {background-color: #FFF6CC; background-image: url(../images/icon_alert.gif); color: #CF8516; }
30
-
31
- .pmpro_message a {color: #345395; }
32
- .pmpro_success a {color: #208A1B; }
33
- .pmpro_error a {color: #E36154; }
34
- .pmpro_alert a {color: #CF8516; }
35
-
36
- /* pagination */
37
- div.pmpro_pagination {padding: 3px; margin: 5px 0px 5px 0px; font-size: 10px; float: right; }
38
- div.pmpro_pagination a {padding: 2px 5px 2px 5px; margin: 1px; border: 1px solid #666; text-decoration: none; /* no underline */ color: #666; background: #EEE; }
39
- div.pmpro_pagination a:hover, div.pmpro_pagination a:active {background: #FFF; }
40
- div.pmpro_pagination span.current {border: 1px solid #FFF; color: #FFF; background: #666; padding: 2px 5px 2px 5px; margin: 1px; font-weight: bold; }
41
- div.pmpro_pagination span.disabled {padding: 2px 5px 2px 5px; margin: 2px; border: 1px solid #BBB; color: #BBB; background: #EFEFEF;}
42
-
43
- p.pmpro_meta_notice {font-size: .6em; padding-top: 5px; border-top: 1px solid #CCC;}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .pmpro_admin {background: url(../images/Paid-Memberships-Pro_watermark.png) bottom right no-repeat !important; padding: 1em 0 70px 0; }
2
+
3
+ .pmpro_admin .pmpro_banner h2 {float: left; }
4
+ .pmpro_admin .pmpro_banner .pmpro_meta {float: left; margin: 26px 0 0 0; font-size: 12px; }
5
+ .pmpro_admin .pmpro_banner .pmpro_meta .pmpro_tag-blue {margin: 0 0 0 5px; }
6
+ .pmpro_admin .pmpro_banner .pmpro_logo {float: left; margin: 0 1em 0 0; width: 350px; height: 75px; }
7
+ .pmpro_admin .pmpro_banner ul.pmpro_menu {clear: both; border: 1px solid #CCC; border-radius: 5px; -moz-border-radius: 5px; background: #FFF; }
8
+ .pmpro_admin .pmpro_banner ul.pmpro_menu li {display: inline-block; margin: 10px 0; padding: 0px 10px; border-right: 1px solid #CCC; }
9
+ .pmpro_admin .pmpro_banner ul.pmpro_menu li a, .pmpro_admin .pmpro_banner ul.pmpro_menu li a:link {color: #1e0741; text-decoration: none; }
10
+ .pmpro_admin .pmpro_banner ul.pmpro_menu li a:hover {text-decoration: underline; color: #412f5b; }
11
+
12
+ .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; }
13
+ .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; }
14
+ .pmpro_admin a.pmpro_tag-blue:hover {background: #77a02e; border: 1px solid #77a02e; }
15
+
16
+ .pmpro_admin .topborder {border-top: 1px solid #CCC; margin-top: 1em; padding-top: 1em; }
17
+ .pmpro_admin #editorcontainer #description {width: 100%; height: 180px; }
18
+ .pmpro_admin .widefat {margin-top: 1em; }
19
+
20
+ .ssp_description #description {width: 100%;}
21
+ .checkbox_box {width: 300px; background: #FFFFFF; border: 1px solid #CCC;}
22
+ .checkbox_box div {border-bottom: 1px solid #CCC; padding: 3px;}
23
+ .checkbox_box .clickable {cursor: pointer;}
24
+ .checkbox_box .clickable:hover {background: #FFC;}
25
+ .top0em {margin-top: 0;}
26
+
27
+ tr.pmpro_gray td {color: #AAA;}
28
+
29
+ /* messages */
30
+ .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; }
31
+
32
+ .pmpro_success {background-color: #CFEECA; background-image: url(../images/icon_success.gif); color: #208A1B; }
33
+ .pmpro_error {background-color: #F9D6CB; background-image: url(../images/icon_error.gif); color: #E36154; }
34
+ .pmpro_alert {background-color: #FFF6CC; background-image: url(../images/icon_alert.gif); color: #CF8516; }
35
+
36
+ .pmpro_message a {color: #345395; }
37
+ .pmpro_success a {color: #208A1B; }
38
+ .pmpro_error a {color: #E36154; }
39
+ .pmpro_alert a {color: #CF8516; }
40
+
41
+ /* highlighted trs */
42
+ tr.pmpro_message {background-image: none;}
43
+ tr.pmpro_success {background-image: none;}
44
+ tr.pmpro_error {background-image: none;}
45
+ tr.pmpro_alert {background-image: none;}
46
+
47
+ /* discount levels */
48
+ .pmpro_discount_levels {border: 1px solid #CCC;}
49
+ .pmpro_discount_levels div {padding: 5px; border: 1px solid #CCC;}
50
+ .pmpro_discount_levels div div {margin-top: 5px; background: #F5F5F5;}
51
+
52
+ /* pagination */
53
+ div.pmpro_pagination {padding: 3px; margin: 5px 0px 5px 0px; font-size: 10px; float: right; }
54
+ div.pmpro_pagination a {padding: 2px 5px 2px 5px; margin: 1px; border: 1px solid #666; text-decoration: none; /* no underline */ color: #666; background: #EEE; }
55
+ div.pmpro_pagination a:hover, div.pmpro_pagination a:active {background: #FFF; }
56
+ div.pmpro_pagination span.current {border: 1px solid #FFF; color: #FFF; background: #666; padding: 2px 5px 2px 5px; margin: 1px; font-weight: bold; }
57
+ div.pmpro_pagination span.disabled {padding: 2px 5px 2px 5px; margin: 2px; border: 1px solid #BBB; color: #BBB; background: #EFEFEF;}
58
+
59
+ p.pmpro_meta_notice {font-size: .8em; padding-top: 5px; border-top: 1px solid #CCC;}
60
+
61
+ /* add ons */
62
+ .pmpro_admin .widgets-holder-wrap {clear: both; margin-top: 20px; padding: 0 8px; }
63
+ .pmpro_admin .widgets-holder-wrap .widget {float: left; width: 32%; margin: 0 1% 1% 0; position: relative; }
64
+ .pmpro_admin .widgets-holder-wrap p.description {padding: 0; }
65
+ .pmpro_admin .widgets-holder-wrap .widget-top {height: auto; cursor: default; }
66
+ .pmpro_admin .widgets-holder-wrap .widget-inside {display: block; height: 130px; overflow: hidden; }
67
+ .pmpro_admin .widgets-holder-wrap .widget-inside p {height: 80px; overflow: hidden; }
68
+ .pmpro_admin #pmpro-gists.widgets-holder-wrap .widget-inside, .pmpro_admin #pmpro-gists.widgets-holder-wrap .widget-inside p {height: auto; }
69
+ .pmpro_admin .widgets-holder-wrap .widget-title { }
70
+ .pmpro_admin .widgets-holder-wrap .widget-title h4 { }
71
+ .pmpro_admin .widgets-holder-wrap .widget-title .status-label {display: block; float: left; margin: 0 5px 0 0; width: 10px;
72
+ height: 10px; overflow: hidden; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; border: 1px solid #DFDFDF; text-indent: -9999em; }
73
+ .pmpro_admin .widgets-holder-wrap .disabled .widget-title .status-label {background: #F00; }
74
+ .pmpro_admin .widgets-holder-wrap .enabled .widget-title .status-label {background: #0C0; }
75
+
76
+ .pmpro_admin .widgets-holder-wrap .widget-title .version {position: absolute; top: 13px; right: 10px; }
77
+ .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;}
78
+
79
+ /*@media (min-width: 1200px) {
80
+ .auto-fold .pmpro_admin .widgets-holder-wrap .widget-inside, .auto-fold .pmpro_admin .widgets-holder-wrap .widget-inside p {height: auto; }
81
+ }
82
+ */
83
+ @media (max-width:900px) {
84
+ .auto-fold .pmpro_admin .widgets-holder-wrap .widget {float: none; width: 100%; }
85
+ .auto-fold .pmpro_admin .widgets-holder-wrap .widget-inside, .auto-fold .pmpro_admin .widgets-holder-wrap .widget-inside p {height: auto; }
86
+ }
87
+
88
+ /* misc */
89
+ .pmpro_lite {color: #AAA;}
90
+ .pmpro_pad20 {padding: 20px !important;}
91
+ .pmpro_red {color: #CC0000;}
92
+ .pmpro_green {color: #00AA00;}
93
+
94
+ /* reports */
95
+ .pmpro_reports-holder { }
96
+ .pmpro_clickable {cursor: pointer;}
97
+ .js .postbox.pmpro_clickable h3 {cursor: pointer;}
css/frontend-rtl.css ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*---------------------------------------
2
+ Buttons
3
+ ---------------------------------------*/
4
+
5
+ /*---------------------------------------
6
+ Forms
7
+ ---------------------------------------*/
8
+ form.pmpro_form div {
9
+ clear: right;
10
+ }
11
+
12
+ form.pmpro_form label {
13
+ float: right;
14
+ margin: 3px 0 0 10px;
15
+ text-align: left;
16
+ }
17
+
18
+ form.pmpro_form .input, form.pmpro_form textarea, .input, form.pmpro_form select {
19
+ margin: 0 0 0 3px;
20
+ }
21
+
22
+ form.pmpro_form .leftmar {
23
+ margin: 8px 130px 0 0;
24
+ }
25
+
26
+ form.pmpro_form .pmpro_captcha {
27
+ margin: 0 130px 0 0 !important;
28
+ }
29
+
30
+ form.pmpro_form .pmpro_submit {
31
+ margin-right: 130px;
32
+ margin-left: auto;
33
+ }
34
+
35
+ form.pmpro_form .pmpro_submit span {
36
+ float: right;
37
+ }
38
+
39
+ form.pmpro_form #pmpro_processing_message {
40
+ margin: 5px 10px 0 0;
41
+ }
42
+
43
+ /*--------------------------------------------------
44
+ Messages - Success, Error, Alert
45
+ ----------------------------------------------------*/
46
+
47
+ .pmpro_content_message a {
48
+ margin: 5px 0 0 5px;
49
+ }
50
+
51
+ /*---------------------------------------
52
+ Membership Checkout
53
+ ---------------------------------------*/
54
+
55
+ .pmpro_checkout ul {
56
+ margin: 5px 20px 0 0;
57
+ }
58
+
59
+ .pmpro_checkout td.rtbdr {
60
+ border-left: 1px solid #CCC;
61
+ border-right: none;
62
+ }
63
+
64
+ .pmpro_thead-msg {
65
+ float: left;
66
+ text-align: left;
67
+ }
68
+
69
+ .pmpro_ordersummary {
70
+ float: left;
71
+ }
72
+
73
+ .pmpro_sslseal {
74
+ float: left;
75
+ }
76
+
77
+ /*---------------------------------------
78
+ Membership Invoice
79
+ ---------------------------------------*/
80
+
81
+ /*---------------------------------------
82
+ Membership Account
83
+ ---------------------------------------*/
84
+
85
+ li.pmpro_more {
86
+ margin-right: -20px;
87
+ padding-right: 0;
88
+ padding-left: 0;
89
+ margin-left: auto;
90
+ }
91
+
92
+ /*---------------------------------------
93
+ Membership Levels
94
+ ---------------------------------------*/
95
+
96
+ /*---------------------------------------
97
+ Misc
98
+ ---------------------------------------*/
99
+ .pmpro_a-right {
100
+ float: left;
101
+ text-align: left;
102
+ }
103
+
104
+ .pmpro_a-print {
105
+ float: left;
106
+ background: url(../images/printer.gif) top right no-repeat;
107
+ padding: 0px 20px 2px 0px;
108
+ }
109
+
110
+
111
+ /* Generated by the RTLer - http://l0uy.com/rtler/ */
css/frontend.css CHANGED
@@ -1,96 +1,174 @@
1
- /*---------------------------------------
2
- Buttons
3
- ---------------------------------------*/
4
- .pmpro_btn {display: inline-block; margin: 0; cursor: pointer; }
5
- .pmpro_btn:hover { }
6
-
7
- /*---------------------------------------
8
- Forms
9
- ---------------------------------------*/
10
- form.pmpro_form div {clear: left; margin: .5em 0 1em 0; }
11
- form.pmpro_form label {float: left; margin: 3px 10px 0 0; width: 120px; font-weight: bold; text-align: right; }
12
- /*form.pmpro_form div div {width: 380px; margin-left: 130px; clear: none;}*/
13
- form.pmpro_form .likelabel {font-weight: bold; }
14
- form.pmpro_form .input, form.pmpro_form textarea, .input {padding: 3px; border: 1px solid #AAA; margin: 0 3px 0 0; }
15
- form.pmpro_form textarea {font-family: Arial, Helvetica, sans-serif; font-size: 12px; }
16
- form.pmpro_form select {margin: 2px 0 0 0 ;}
17
- form.pmpro_form .lite {color: #666; }
18
- form.pmpro_form .leftmar {margin: 8px 0 0 130px; }
19
-
20
- form.pmpro_form .pmpro_captcha {margin: 0 0 0 130px !important; }
21
- form.pmpro_form .pmpro_captcha div {clear: none; margin: 0; }
22
-
23
- /*--------------------------------------------------
24
- Messages - Success, Error, Alert
25
- ----------------------------------------------------*/
26
- .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; }
27
-
28
- .pmpro_success {background-color: #CFEECA; background-image: url(../images/icon_success.gif); color: #208A1B; }
29
- .pmpro_error {background-color: #F9D6CB; background-image: url(../images/icon_error.gif); color: #E36154; }
30
- .pmpro_alert {background-color: #FFF6CC; background-image: url(../images/icon_alert.gif); color: #CF8516; }
31
-
32
- .pmpro_message a {color: #345395; }
33
- .pmpro_success a {color: #208A1B; }
34
- .pmpro_error a {color: #E36154; }
35
- .pmpro_alert a {color: #CF8516; }
36
-
37
- /*---------------------------------------
38
- Membership Checkout
39
- ---------------------------------------*/
40
- .pmpro_checkout thead th {font-weight: bold; color: #444; padding: 10px; }
41
- .pmpro_checkout tbody td {padding: 10px; }
42
- .pmpro_checkout tr.odd td {background: #FAFAFA; }
43
- .pmpro_checkout tr.selected td {background: #FFC; }
44
- .pmpro_checkout tr.active td {background: #FFC; }
45
- .pmpro_checkout .name {font-weight: bold; }
46
- .pmpro_checkout ul {margin: 5px 0 0 20px; padding: 0; font-size: .8em; color: #444; }
47
-
48
- .pmpro_checkout tfoot td {padding: 10px; color: #444; }
49
- .pmpro_checkout .topfoot td {border-top: 2px solid #CCC;}
50
- .pmpro_checkout .total td {border-top: 1px solid #CCC; font-size: 1.2em; font-weight: bold; padding-bottom: 30px;}
51
- .pmpro_checkout tfoot .entercode td {background: #EEE; }
52
-
53
- .pmpro_checkout td.rtbdr {border-right: 1px solid #CCC; }
54
-
55
- .pmpro_checkout select {font-size: 11px; }
56
-
57
- .pmpro_thead-msg {display: block; float: right; width: auto; font-style: italic; font-weight: normal; text-align: right; }
58
-
59
- .pmpro_ordersummary {float: right; }
60
-
61
- #pmpro_license { background: #FFF; padding: 5px; border: 1px solid #CCC; height: 200px; margin: 3px; color: #666; overflow: auto; }
62
-
63
- .pmpro_sslseal {float: right; clear: none !important; margin: 0 !important; }
64
-
65
- /*---------------------------------------
66
- Membership Invoice
67
- ---------------------------------------*/
68
- .pmpro_invoice { }
69
-
70
-
71
- /*---------------------------------------
72
- Membership Account
73
- ---------------------------------------*/
74
- .pmpro_left {float: left; width: 49%; }
75
- .pmpro_right {float: right; width: 49%; }
76
-
77
- .pmpro_box {border: 1px solid #CCC; padding: 1em; margin: 0 0 1em 0; }
78
- .pmpro_box h3 {border:none; background: none; border-bottom: 1px solid #CCC; padding: 0 0 .5em 0; margin: 0 0 .5em 0; }
79
-
80
- .pmpro_hidden {display: none;}
81
- li.pmpro_more {list-style-type: none; text-align: center; margin-left: -20px; padding-left: 0;}
82
-
83
-
84
- /*---------------------------------------
85
- Misc
86
- ---------------------------------------*/
87
- .pmpro_a-right {float: right; width: auto; text-align: right; text-decoration: underline; font-size: 11px; }
88
- .pmpro_a-print {float: right; width: auto; text-decoration: none; color: #345395; background: url(../images/printer.gif) top left no-repeat; padding: 0px 0px 2px 20px; font-size: 11px; line-height: 16px; cursor: pointer; }
89
-
90
- .pmpro_red {color: #CC0000; }
91
- .pmpro_grey {color: #999; }
92
-
93
- .top1em {margin-top: 1em;}
94
- .bot1em {margin-bottom: 1em;}
95
- .bot0em {margin-bottom: 0em;}
96
- .clear {clear: both; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*---------------------------------------
2
+ Buttons
3
+ ---------------------------------------*/
4
+ .pmpro_btn, .pmpro_btn:link, .pmpro_content_message a, .pmpro_content_message a:link {
5
+ display: inline-block;
6
+ background-color: #EFEFEF;
7
+ background-image: none;
8
+ border: 1px solid #D6D6D6;
9
+ -webkit-border-radius: 4px;
10
+ -moz-border-radius: 4px;
11
+ border-radius: 4px;
12
+ padding: 6px 12px;
13
+ margin: 0;
14
+ color: #444;
15
+ font-size: 12px;
16
+ font-weight: 700;
17
+ text-transform: none;
18
+ text-decoration: none;
19
+ text-align: center;
20
+ white-space: nowrap;
21
+ vertical-align: middle;
22
+ cursor: pointer;
23
+ -webkit-user-select: none;
24
+ -moz-user-select: none;
25
+ -ms-user-select: none;
26
+ -o-user-select: none;
27
+ user-select: none;
28
+ }
29
+
30
+ .pmpro_btn:focus, .pmpro_content_message a:focus {
31
+ outline: thin dotted;
32
+ outline: 5px auto -webkit-focus-ring-color;
33
+ outline-offset: -2px;
34
+ }
35
+
36
+ .pmpro_btn:hover, .pmpro_btn:focus, .pmpro_content_message a:focus, .pmpro_content_message a:hover {
37
+ color: #000;
38
+ background-color: #FAFAFA;
39
+ text-decoration: none;
40
+ }
41
+
42
+ .pmpro_btn:active,
43
+ .pmpro_btn.active {
44
+ background-image: none;
45
+ outline: 0;
46
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
47
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
48
+ }
49
+
50
+ .pmpro_btn.disabled,
51
+ .pmpro_btn[disabled],
52
+ fieldset[disabled] .pmpro_btn {
53
+ pointer-events: none;
54
+ cursor: not-allowed;
55
+ opacity: 0.65;
56
+ filter: alpha(opacity=65);
57
+ -webkit-box-shadow: none;
58
+ box-shadow: none;
59
+ }
60
+
61
+ /*---------------------------------------
62
+ Forms
63
+ ---------------------------------------*/
64
+ form.pmpro_form div {clear: left; margin: .5em 0 1em 0; }
65
+ form.pmpro_form label {float: left; margin: 3px 10px 0 0; width: 120px; font-weight: bold; text-align: right; }
66
+ form.pmpro_form label.pmpro_normal {float: none; margin: 0 0 0 0; width: auto; font-weight: normal; text-align: auto;}
67
+ .pmpro_clickable {cursor: pointer;}
68
+ form.pmpro_form .likelabel {font-weight: bold; }
69
+ form.pmpro_form .input, form.pmpro_form textarea, .input, form.pmpro_form select {padding: 3px; border: 1px solid #AAA; margin: 0 3px 0 0; }
70
+ form.pmpro_form textarea {font-family: Arial, Helvetica, sans-serif; font-size: 12px; }
71
+ form.pmpro_form select {margin: 2px 0 0 0 ; font-size: 12px;}
72
+ form.pmpro_form .lite {color: #666; }
73
+ form.pmpro_form .leftmar {margin: 8px 0 0 130px; }
74
+
75
+ form.pmpro_form .pmpro_captcha {margin: 0 0 0 130px !important; }
76
+ form.pmpro_form .pmpro_captcha div {clear: none; margin: 0; }
77
+ form.pmpro_form .pmpro_submit {margin-left: 130px; }
78
+ form.pmpro_form .pmpro_submit span {float: left; }
79
+ form.pmpro_form #pmpro_processing_message {margin: 5px 0 0 10px; font-style: italic; color: #999; }
80
+
81
+ /*--------------------------------------------------
82
+ Messages - Success, Error, Alert
83
+ ----------------------------------------------------*/
84
+ .pmpro_message {background-color: #d9edf7; margin: .5em 0; padding: 10px 15px; color: #31708f; font-size: 14px; font-weight: 400; line-height: 1.5em; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; border: 1px solid #bce8f1; }
85
+
86
+ .pmpro_success {background-color: #dff0d8; color: #3c763d; border-color: #bce8f1; }
87
+ .pmpro_error {background-color: #f2dede; color: #a94442; border-color: #ebccd1; }
88
+ .pmpro_alert {background-color: #fcf8e3; color: #8a6d3b; border-color: #faebcc;}
89
+
90
+ .pmpro_content_message a {margin: 5px 5px 0 0; }
91
+
92
+ .pmpro_message a {color: #245269; text-decoration: underline; }
93
+ .pmpro_success a {color: #2b542c; }
94
+ .pmpro_error a {color: #843534; }
95
+ .pmpro_alert a {color: #66512c; }
96
+
97
+ input.pmpro_error {background-image: none;}
98
+ select.pmpro_error {background-image: none;}
99
+
100
+ /*---------------------------------------
101
+ Membership Checkout
102
+ ---------------------------------------*/
103
+ .pmpro_checkout thead th {font-weight: bold; color: #444; padding: 10px; }
104
+ .pmpro_checkout tbody td {padding: 10px; }
105
+ .pmpro_checkout tr.odd td {background: rgba(125,125,125,.1); }
106
+ .pmpro_checkout tr.selected td {background: #FFC; }
107
+ .pmpro_checkout tr.active td {background: #FFC; }
108
+ .pmpro_checkout .name {font-weight: bold; }
109
+ .pmpro_checkout ul {margin: 5px 0 0 20px; padding: 0; font-size: .8em; color: #444; }
110
+
111
+ .pmpro_checkout tfoot td {padding: 10px; color: #444; }
112
+ .pmpro_checkout .topfoot td {border-top: 2px solid #CCC;}
113
+ .pmpro_checkout .total td {border-top: 1px solid #CCC; font-size: 1.2em; font-weight: bold; padding-bottom: 30px;}
114
+ .pmpro_checkout tfoot .entercode td {background: #EEE; }
115
+
116
+ .pmpro_checkout td.rtbdr {border-right: 1px solid #CCC; }
117
+
118
+ .pmpro_checkout select {font-size: 11px; }
119
+
120
+ .pmpro_thead-msg {display: block; float: right; width: auto; font-style: italic; font-weight: normal; text-align: right; white-space: nowrap; }
121
+
122
+ .pmpro_ordersummary {float: right; }
123
+
124
+ #pmpro_license { background: #FFF; padding: 5px; border: 1px solid #CCC; height: 200px; margin: 3px; color: #666; overflow: auto; }
125
+
126
+ .pmpro_sslseal {float: right; clear: none !important; margin: 0 !important; }
127
+
128
+ a.pmpro_radio {text-decoration: none; color: #000;}
129
+
130
+ /*---------------------------------------
131
+ Membership Invoice
132
+ ---------------------------------------*/
133
+ .pmpro_invoice { }
134
+
135
+
136
+ /*---------------------------------------
137
+ Membership Account
138
+ ---------------------------------------*/
139
+ #pmpro_account .pmpro_box {border-top: 1px solid #CCC; padding: 1em 0; margin: 1em 0; }
140
+ #pmpro_account .pmpro_box h3 {margin: 0; padding: 0; border: none; background: none; }
141
+ #pmpro_account .pmpro_box p {margin: .5em 0 0 0; padding: 0; }
142
+ #pmpro_account .pmpro_box ul {margin-bottom: 0; }
143
+
144
+ #pmpro_account #pmpro_account-membership { }
145
+ #pmpro_account #pmpro_account-profile { }
146
+ #pmpro_account #pmpro_account-billing { }
147
+ #pmpro_account #pmpro_account-invoices { }
148
+ #pmpro_account #pmpro_account-links { }
149
+
150
+
151
+ .pmpro_hidden {display: none;}
152
+ li.pmpro_more {list-style-type: none; text-align: center; margin-left: -20px; padding-left: 0;}
153
+
154
+ /*---------------------------------------
155
+ Membership Levels
156
+ ---------------------------------------*/
157
+ #pmpro_levels_table {background: #FFF; }
158
+ #pmpro_levels_table .pmpro_btn {display: block; }
159
+
160
+ /*---------------------------------------
161
+ Misc
162
+ ---------------------------------------*/
163
+ .pmpro_a-right {float: right; width: auto; text-align: right; text-decoration: underline; font-size: 11px; }
164
+ .pmpro_a-print {float: right; width: auto; text-decoration: none; color: #345395; background: url(../images/printer.gif) top left no-repeat; padding: 0px 0px 2px 20px; font-size: 11px; line-height: 16px; cursor: pointer; }
165
+
166
+ .pmpro_red {color: #CC0000; }
167
+ .pmpro_grey {color: #999; }
168
+
169
+ .top1em {margin-top: 1em;}
170
+ .bot1em {margin-bottom: 1em;}
171
+ .bot0em {margin-bottom: 0em;}
172
+ .clear {clear: both; }
173
+
174
+ .pmpro_small {font-size: .8em;}
email/admin_change.html CHANGED
@@ -1,6 +1,6 @@
1
  <p>An administrator at !!sitename!! has changed your membership level.</p>
2
 
3
- <p>Your !!membership_change!!.</p>
4
 
5
  <p>If you did not request this membership change and would like more information please contact us at !!siteemail!!</p>
6
 
1
  <p>An administrator at !!sitename!! has changed your membership level.</p>
2
 
3
+ <p>!!membership_change!!.</p>
4
 
5
  <p>If you did not request this membership change and would like more information please contact us at !!siteemail!!</p>
6
 
email/admin_change_admin.html ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <p>An administrator at !!sitename!! has changed a membership level.</p>
2
+
3
+ <p>!!membership_change!!.</p>
4
+
5
+ <p>Log in to your WordPress admin here: !!login_link!!</p>
email/billing.html CHANGED
@@ -3,10 +3,7 @@
3
  <p>Account: !!display_name!! (!!user_email!!)</p>
4
  <p>
5
  Billing Information:<br />
6
- !!billing_name!!<br />
7
- !!billing_street!!<br />
8
- !!billing_city!!, !!billing_state!! !!billing_zip!!<br />
9
- !!billing_phone!!
10
  </p>
11
 
12
  <p>
3
  <p>Account: !!display_name!! (!!user_email!!)</p>
4
  <p>
5
  Billing Information:<br />
6
+ !!billing_address!!
 
 
 
7
  </p>
8
 
9
  <p>
email/billing_admin.html ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>The billing information for !!display_name!! at !!sitename!! has been changed.</p>
2
+
3
+ <p>Account: !!display_name!! (!!user_email!!)</p>
4
+ <p>
5
+ Billing Information:<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
+ Expires: !!expirationmonth!!/!!expirationyear!!
15
+ </p>
16
+
17
+ <p>Log in to your WordPress dashboard here: !!login_link!!</p>
email/billing_failure.html CHANGED
@@ -3,11 +3,7 @@
3
  <p>Account: !!display_name!! (!!user_email!!)</p>
4
  <p>The most recent account information we have on file is:</p>
5
 
6
- <p>!!billing_name!!</br />
7
- !!billing_street!!<br />
8
- !!billing_city!!, !!billing_state!! !!billing_zip!!<br />
9
- !!billing_phone!!
10
- </p>
11
 
12
  <p>
13
  !!cardtype!!: !!accountnumber!!<br />
3
  <p>Account: !!display_name!! (!!user_email!!)</p>
4
  <p>The most recent account information we have on file is:</p>
5
 
6
+ <p>!!billing_address!!</p>
 
 
 
 
7
 
8
  <p>
9
  !!cardtype!!: !!accountnumber!!<br />
email/billing_failure_admin.html CHANGED
@@ -3,11 +3,7 @@
3
  <p>Account: !!display_name!! (!!user_email!!)</p>
4
  <p>The most recent account information we have on file is:</p>
5
 
6
- <p>!!billing_name!!</br />
7
- !!billing_street!!<br />
8
- !!billing_city!!, !!billing_state!! !!billing_zip!!<br />
9
- !!billing_phone!!
10
- </p>
11
 
12
  <p>
13
  !!cardtype!!: !!accountnumber!!<br />
3
  <p>Account: !!display_name!! (!!user_email!!)</p>
4
  <p>The most recent account information we have on file is:</p>
5
 
6
+ <p>!!billing_address!!</p>
 
 
 
 
7
 
8
  <p>
9
  !!cardtype!!: !!accountnumber!!<br />
email/cancel.html CHANGED
@@ -1,3 +1,3 @@
1
- <p>Your membership at !!sitename!! has been canceled.</p>
2
 
3
  <p>If you did not request this cancellation and would like more information please contact us at !!siteemail!!</p>
1
+ <p>Your membership at !!sitename!! has been cancelled.</p>
2
 
3
  <p>If you did not request this cancellation and would like more information please contact us at !!siteemail!!</p>
email/cancel_admin.html ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <p>The membership for !!user_login!! at !!sitename!! has been cancelled.</p>
2
+
3
+ <p>Account: !!display_name!! (!!user_email!!)</p>
4
+ <p>Membership Level: !!membership_level_name!!</p>
5
+ <p>Start Date: !!startdate!!</p>
6
+ <p>Cancellation Date: !!enddate!!</p>
7
+
8
+ <p>Log in to your WordPress admin here: !!login_link!!</p>
email/checkout_check.html ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Thank you for your membership to !!sitename!!. Your membership account is now active.</p>
2
+
3
+ !!instructions!!
4
+
5
+ <p>Below are details about your membership account and a receipt for your initial membership invoice.</p>
6
+
7
+ <p>Account: !!display_name!! (!!user_email!!)</p>
8
+ <p>Membership Level: !!membership_level_name!!</p>
9
+ <p>Membership Fee: !!membership_cost!!</p>
10
+ !!membership_expiration!! !!discount_code!!
11
+
12
+ <p>
13
+ Invoice #!!invoice_id!! on !!invoice_date!!<br />
14
+ Total Billed: !!invoice_total!!
15
+ </p>
16
+
17
+ <p>Log in to your membership account here: !!login_link!!</p>
email/checkout_check_admin.html ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>There was a new member checkout at !!sitename!!.</p>
2
+
3
+ <p><strong>They have chosen to pay by check.</strong></p>
4
+
5
+ <p>Below are details about the new membership account and a receipt for the initial membership invoice.</p>
6
+
7
+ <p>Account: !!display_name!! (!!user_email!!)</p>
8
+ <p>Membership Level: !!membership_level_name!!</p>
9
+ <p>Membership Fee: !!membership_cost!!</p>
10
+ !!membership_expiration!! !!discount_code!!
11
+
12
+ <p>
13
+ Invoice #!!invoice_id!! on !!invoice_date!!<br />
14
+ Total Billed: $!!invoice_total!!
15
+ </p>
16
+
17
+ <p>Log in to your membership account here: !!login_link!!</p>
email/checkout_express.html ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>Thank you for your membership to !!sitename!!. Your membership account is now active.</p>
2
+ <p>Below are details about your membership account and a receipt for your initial membership invoice.</p>
3
+
4
+ <p>Account: !!display_name!! (!!user_email!!)</p>
5
+ <p>Membership Level: !!membership_level_name!!</p>
6
+ <p>Membership Fee: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
+
9
+ <p>
10
+ Invoice #!!invoice_id!! on !!invoice_date!!<br />
11
+ Total Billed: !!invoice_total!!
12
+ </p>
13
+
14
+ <p>Log in to your membership account here: !!login_link!!</p>
email/checkout_express_admin.html ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>There was a new member checkout at !!sitename!!.</p>
2
+ <p>Below are details about the new membership account and a receipt for the initial membership invoice.</p>
3
+
4
+ <p>Account: !!display_name!! (!!user_email!!)</p>
5
+ <p>Membership Level: !!membership_level_name!!</p>
6
+ <p>Membership Fee: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
+
9
+ <p>
10
+ Invoice #!!invoice_id!! on !!invoice_date!!<br />
11
+ Total Billed: !!invoice_total!!
12
+ </p>
13
+
14
+ <p>Log in to your membership account here: !!login_link!!</p>
email/checkout_free.html CHANGED
@@ -3,5 +3,6 @@
3
 
4
  <p>Account: !!display_name!! (!!user_email!!)</p>
5
  <p>Membership Level: !!membership_level_name!!</p>
 
6
 
7
  <p>Log in to your membership account here: !!login_link!!</p>
3
 
4
  <p>Account: !!display_name!! (!!user_email!!)</p>
5
  <p>Membership Level: !!membership_level_name!!</p>
6
+ !!membership_expiration!! !!discount_code!!
7
 
8
  <p>Log in to your membership account here: !!login_link!!</p>
email/checkout_free_admin.html ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <p>There was a new member checkout at !!sitename!!.</p>
2
+ <p>Below are details about the new membership account.</p>
3
+
4
+ <p>Account: !!display_name!! (!!user_email!!)</p>
5
+ <p>Membership Level: !!membership_level_name!!</p>
6
+ !!membership_expiration!! !!discount_code!!
7
+
8
+ <p>Log in to your membership account here: !!login_link!!</p>
email/checkout_freetrial.html CHANGED
@@ -4,13 +4,11 @@
4
  <p>Account: !!display_name!! (!!user_email!!)</p>
5
  <p>Membership Level: !!membership_level_name!!</p>
6
  <p>Membership Fee: !!membership_cost!!</p>
 
7
 
8
  <p>
9
  Billing Information on File:<br />
10
- !!billing_name!!<br />
11
- !!billing_street!!<br />
12
- !!billing_city!!, !!billing_state!! !!billing_zip!!<br />
13
- !!billing_phone!!
14
  </p>
15
 
16
  <p>
4
  <p>Account: !!display_name!! (!!user_email!!)</p>
5
  <p>Membership Level: !!membership_level_name!!</p>
6
  <p>Membership Fee: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
 
9
  <p>
10
  Billing Information on File:<br />
11
+ !!billing_address!!
 
 
 
12
  </p>
13
 
14
  <p>
email/checkout_freetrial_admin.html ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>There was a new member checkout at !!sitename!!.</p>
2
+ <p>Below are details about the new membership account and a receipt for the initial membership invoice.</p>
3
+
4
+ <p>Account: !!display_name!! (!!user_email!!)</p>
5
+ <p>Membership Level: !!membership_level_name!!</p>
6
+ <p>Membership Fee: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
+
9
+ <p>
10
+ Billing Information on File:<br />
11
+ !!billing_address!!
12
+ </p>
13
+
14
+ <p>
15
+ !!cardtype!!: !!accountnumber!!<br />
16
+ Expires: !!expirationmonth!!/!!expirationyear!!
17
+ </p>
18
+
19
+ <p>Log in to your membership account here: !!login_link!!</p>
email/checkout_paid.html CHANGED
@@ -4,17 +4,15 @@
4
  <p>Account: !!display_name!! (!!user_email!!)</p>
5
  <p>Membership Level: !!membership_level_name!!</p>
6
  <p>Membership Fee: !!membership_cost!!</p>
 
7
 
8
  <p>
9
  Invoice #!!invoice_id!! on !!invoice_date!!<br />
10
- Total Billed: $!!invoice_total!!
11
  </p>
12
  <p>
13
  Billing Information:<br />
14
- !!billing_name!!<br />
15
- !!billing_street!!<br />
16
- !!billing_city!!, !!billing_state!! !!billing_zip!!<br />
17
- !!billing_phone!!
18
  </p>
19
 
20
  <p>
4
  <p>Account: !!display_name!! (!!user_email!!)</p>
5
  <p>Membership Level: !!membership_level_name!!</p>
6
  <p>Membership Fee: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
 
9
  <p>
10
  Invoice #!!invoice_id!! on !!invoice_date!!<br />
11
+ Total Billed: !!invoice_total!!
12
  </p>
13
  <p>
14
  Billing Information:<br />
15
+ !!billing_address!!
 
 
 
16
  </p>
17
 
18
  <p>
email/checkout_paid_admin.html ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>There was a new member checkout at !!sitename!!.</p>
2
+ <p>Below are details about the new membership account and a receipt for the initial membership invoice.</p>
3
+
4
+ <p>Account: !!display_name!! (!!user_email!!)</p>
5
+ <p>Membership Level: !!membership_level_name!!</p>
6
+ <p>Membership Fee: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
+
9
+ <p>
10
+ Invoice #!!invoice_id!! on !!invoice_date!!<br />
11
+ Total Billed: !!invoice_total!!
12
+ </p>
13
+ <p>
14
+ Billing Information:<br />
15
+ !!billing_address!!
16
+ </p>
17
+
18
+ <p>
19
+ !!cardtype!!: !!accountnumber!!<br />
20
+ Expires: !!expirationmonth!!/!!expirationyear!!
21
+ </p>
22
+
23
+ <p>Log in to your membership account here: !!login_link!!</p>
email/checkout_trial.html CHANGED
@@ -4,16 +4,15 @@
4
  <p>Account: !!display_name!! (!!user_email!!)</p>
5
  <p>Membership Level: !!membership_level_name!!</p>
6
  <p>Membership Fee: !!membership_cost!!</p>
 
 
7
  <p>
8
  Invoice #!!invoice_id!! on !!invoice_date!!<br />
9
- Total Billed: $!!invoice_total!!
10
  </p>
11
  <p>
12
  Billing Information:<br />
13
- !!billing_name!!<br />
14
- !!billing_street!!<br />
15
- !!billing_city!!, !!billing_state!! !!billing_zip!!<br />
16
- !!billing_phone!!
17
  </p>
18
 
19
  <p>
4
  <p>Account: !!display_name!! (!!user_email!!)</p>
5
  <p>Membership Level: !!membership_level_name!!</p>
6
  <p>Membership Fee: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
+
9
  <p>
10
  Invoice #!!invoice_id!! on !!invoice_date!!<br />
11
+ Total Billed: !!invoice_total!!
12
  </p>
13
  <p>
14
  Billing Information:<br />
15
+ !!billing_address!!
 
 
 
16
  </p>
17
 
18
  <p>
email/checkout_trial_admin.html ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>There was a new member checkout at !!sitename!!.</p>
2
+ <p>Below are details about the new membership account and a receipt for the initial membership invoice.</p>
3
+
4
+ <p>Account: !!display_name!! (!!user_email!!)</p>
5
+ <p>Membership Level: !!membership_level_name!!</p>
6
+ <p>Membership Fee: !!membership_cost!!</p>
7
+ !!membership_expiration!! !!discount_code!!
8
+
9
+ <p>
10
+ Invoice #!!invoice_id!! on !!invoice_date!!<br />
11
+ Total Billed: !!invoice_total!!
12
+ </p>
13
+ <p>
14
+ Billing Information:<br />
15
+ !!billing_address!!
16
+ </p>
17
+
18
+ <p>
19
+ !!cardtype!!: !!accountnumber!!<br />
20
+ Expires: !!expirationmonth!!/!!expirationyear!!
21
+ </p>
22
+
23
+ <p>Log in to your membership account here: !!login_link!!</p>
email/credit_card_expiring.html ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p>The payment method used for your membership at !!sitename!! will expire soon. <strong>Please click the following link to log in and update your billing information to avoid account suspension. !!login_link!!</strong></p>
2
+
3
+ <p>Account: !!display_name!! (!!user_email!!)</p>
4
+ <p>The most recent account information we have on file is:</p>
5
+
6
+ <p>!!billing_name!!</br />
7
+ !!billing_address!!
8
+ </p>
9
+
10
+ <p>
11
+ !!cardtype!!: !!accountnumber!!<br />
12
+ Expires: !!expirationmonth!!/!!expirationyear!!
13
+ </p>
email/invoice.html CHANGED
@@ -3,14 +3,11 @@
3
  <p>Account: !!display_name!! (!!user_email!!)</p>
4
  <p>
5
  Invoice #!!invoice_id!! on !!invoice_date!!<br />
6
- Total Billed: $!!invoice_total!!
7
  </p>
8
  <p>
9
  Billing Information:<br />
10
- !!billing_name!!<br />
11
- !!billing_street!!<br />
12
- !!billing_city!!, !!billing_state!! !!billing_zip!!<br />
13
- !!billing_phone!!
14
  </p>
15
 
16
  <p>
3
  <p>Account: !!display_name!! (!!user_email!!)</p>
4
  <p>
5
  Invoice #!!invoice_id!! on !!invoice_date!!<br />
6
+ Total Billed: !!invoice_total!!
7
  </p>
8
  <p>
9
  Billing Information:<br />
10
+ !!billing_address!!
 
 
 
11
  </p>
12
 
13
  <p>
email/membership_expired.html ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <p>Your membership at !!sitename!! has ended.</p>
2
+
3
+ <p>Thank you for your support.</p>
4
+
5
+ <p>View our current membership offerings here: !!levels_link!!</p>
6
+
7
+ <p>Log in to manage your account here: !!login_link!!</p>
email/membership_expiring.html ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <p>Thank you for your membership to !!sitename!!. This is just a reminder that your membership will end on !!enddate!!.</p>
2
+
3
+ <p>Account: !!display_name!! (!!user_email!!)</p>
4
+ <p>Membership Level: !!membership_level_name!!</p>
5
+
6
+ <p>Log in to your membership account here: !!login_link!!</p>
email/trial_ending.html CHANGED
@@ -1,20 +1,8 @@
1
  <p>Thank you for your membership to !!sitename!!. Your trial period is ending on !!trial_end!!.</p>
2
- <p>Below are details about your membership account.</p>
3
 
4
  <p>Account: !!display_name!! (!!user_email!!)</p>
5
  <p>Membership Level: !!membership_level_name!!</p>
6
- <p>Membership Fee: !!membership_cost!!</p>
7
- <p>
8
- Billing Information on File:<br />
9
- !!billing_name!!<br />
10
- !!billing_street!!<br />
11
- !!billing_city!!, !!billing_state!! !!billing_zip!!<br />
12
- !!billing_phone!!
13
- </p>
14
-
15
- <p>
16
- !!cardtype!!: !!accountnumber!!<br />
17
- Expires: !!expirationmonth!!/!!expirationyear!!
18
- </p>
19
 
20
  <p>Log in to your membership account here: !!login_link!!</p>
1
  <p>Thank you for your membership to !!sitename!!. Your trial period is ending on !!trial_end!!.</p>
 
2
 
3
  <p>Account: !!display_name!! (!!user_email!!)</p>
4
  <p>Membership Level: !!membership_level_name!!</p>
5
+
6
+ <p>Your fee will be changing from !!trial_amount!! to !!billing_amount!! every !!cycle_number!! !!cycle_period!!(s).</p>
 
 
 
 
 
 
 
 
 
 
 
7
 
8
  <p>Log in to your membership account here: !!login_link!!</p>
images/Paid-Memberships-Pro.png ADDED
Binary file
images/Paid-Memberships-Pro_watermark.png ADDED
Binary file
images/bg_grad-chrome.gif ADDED
Binary file
images/bg_grad-grey.gif ADDED
Binary file
images/icon-pmproadmin16-sprite.png ADDED
Binary file
images/icon-pmproadmin16-sprite_2x.png ADDED
Binary file
images/icon-pmproadmin32.png ADDED
Binary file
images/icon-pmproadmin32_2x.png ADDED
Binary file
includes/adminpages.php ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Get array of PMPro Capabilities
4
+ */
5
+ function pmpro_getPMProCaps()
6
+ {
7
+ $pmpro_caps = array(
8
+ //pmpro_memberships_menu //this controls viewing the menu itself
9
+ 'pmpro_membershiplevels',
10
+ 'pmpro_pagesettings',
11
+ 'pmpro_paymentsettings',
12
+ 'pmpro_emailsettings',
13
+ 'pmpro_advancedsettings',
14
+ 'pmpro_addons',
15
+ 'pmpro_memberslist',
16
+ 'pmpro_reports',
17
+ 'pmpro_orders',
18
+ 'pmpro_discountcodes'
19
+ );
20
+
21
+ return $pmpro_caps;
22
+ }
23
+
24
+ /*
25
+ Dashboard Menu
26
+ */
27
+ function pmpro_add_pages()
28
+ {
29
+ global $wpdb;
30
+
31
+ //array of all caps in the menu
32
+ $pmpro_caps = pmpro_getPMProCaps();
33
+
34
+ //the top level menu links to the first page they have access to
35
+ foreach($pmpro_caps as $cap)
36
+ {
37
+ if(current_user_can($cap))
38
+ {
39
+ $top_menu_cap = $cap;
40
+ break;
41
+ }
42
+ }
43
+
44
+ if(empty($top_menu_cap))
45
+ return;
46
+
47
+ add_menu_page(__('Memberships', 'pmpro'), __('Memberships', 'pmpro'), 'pmpro_memberships_menu', 'pmpro-membershiplevels', $top_menu_cap, PMPRO_URL . '/images/menu_users.png');
48
+ add_submenu_page('pmpro-membershiplevels', __('Page Settings', 'pmpro'), __('Page Settings', 'pmpro'), 'pmpro_pagesettings', 'pmpro-pagesettings', 'pmpro_pagesettings');
49
+ add_submenu_page('pmpro-membershiplevels', __('Payment Settings', 'pmpro'), __('Payment Settings', 'pmpro'), 'pmpro_paymentsettings', 'pmpro-paymentsettings', 'pmpro_paymentsettings');
50
+ add_submenu_page('pmpro-membershiplevels', __('Email Settings', 'pmpro'), __('Email Settings', 'pmpro'), 'pmpro_emailsettings', 'pmpro-emailsettings', 'pmpro_emailsettings');
51
+ add_submenu_page('pmpro-membershiplevels', __('Advanced Settings', 'pmpro'), __('Advanced Settings', 'pmpro'), 'pmpro_advancedsettings', 'pmpro-advancedsettings', 'pmpro_advancedsettings');
52
+ add_submenu_page('pmpro-membershiplevels', __('Add Ons', 'pmpro'), __('Add Ons', 'pmpro'), 'pmpro_addons', 'pmpro-addons', 'pmpro_addons');
53
+ add_submenu_page('pmpro-membershiplevels', __('Members List', 'pmpro'), __('Members List', 'pmpro'), 'pmpro_memberslist', 'pmpro-memberslist', 'pmpro_memberslist');
54
+ add_submenu_page('pmpro-membershiplevels', __('Reports', 'pmpro'), __('Reports', 'pmpro'), 'pmpro_reports', 'pmpro-reports', 'pmpro_reports');
55
+ add_submenu_page('pmpro-membershiplevels', __('Orders', 'pmpro'), __('Orders', 'pmpro'), 'pmpro_orders', 'pmpro-orders', 'pmpro_orders');
56
+ add_submenu_page('pmpro-membershiplevels', __('Discount Codes', 'pmpro'), __('Discount Codes', 'pmpro'), 'pmpro_discountcodes', 'pmpro-discountcodes', 'pmpro_discountcodes');
57
+
58
+ //rename the automatically added Memberships submenu item
59
+ global $submenu;
60
+ if(!empty($submenu['pmpro-membershiplevels']))
61
+ {
62
+ if(current_user_can("pmpro_membershiplevels"))
63
+ {
64
+ $submenu['pmpro-membershiplevels'][0][0] = __( 'Membership Levels', 'pmpro' );
65
+ $submenu['pmpro-membershiplevels'][0][3] = __( 'Membership Levels', 'pmpro' );
66
+ }
67
+ else
68
+ {
69
+ unset($submenu['pmpro-membershiplevels']);
70
+ }
71
+ }
72
+ }
73
+ add_action('admin_menu', 'pmpro_add_pages');
74
+
75
+ /*
76
+ Admin Bar
77
+ */
78
+ function pmpro_admin_bar_menu() {
79
+ global $wp_admin_bar;
80
+
81
+ //view menu at all?
82
+ if ( !current_user_can('pmpro_memberships_menu') || !is_admin_bar_showing() )
83
+ return;
84
+
85
+ //array of all caps in the menu
86
+ $pmpro_caps = pmpro_getPMProCaps();
87
+
88
+ //the top level menu links to the first page they have access to
89
+ foreach($pmpro_caps as $cap)
90
+ {
91
+ if(current_user_can($cap))
92
+ {
93
+ $top_menu_page = str_replace("_", "-", $cap);
94
+ break;
95
+ }
96
+ }
97
+
98
+ $wp_admin_bar->add_menu( array(
99
+ 'id' => 'paid-memberships-pro',
100
+ 'title' => __( 'Memberships', 'pmpro'),
101
+ 'href' => get_admin_url(NULL, '/admin.php?page=' . $top_menu_page) ) );
102
+
103
+ if(current_user_can('pmpro_membershiplevels'))
104
+ $wp_admin_bar->add_menu( array(
105
+ 'id' => 'pmpro-membership-levels',
106
+ 'parent' => 'paid-memberships-pro',
107
+ 'title' => __( 'Membership Levels', 'pmpro'),
108
+ 'href' => get_admin_url(NULL, '/admin.php?page=pmpro-membershiplevels') ) );
109
+
110
+ if(current_user_can('pmpro_pagesettings'))
111
+ $wp_admin_bar->add_menu( array(
112
+ 'id' => 'pmpro-page-settings',
113
+ 'parent' => 'paid-memberships-pro',
114
+ 'title' => __( 'Page Settings', 'pmpro'),
115
+ 'href' => get_admin_url(NULL, '/admin.php?page=pmpro-pagesettings') ) );
116
+
117
+ if(current_user_can('pmpro_paymentsettings'))
118
+ $wp_admin_bar->add_menu( array(
119
+ 'id' => 'pmpro-payment-settings',
120
+ 'parent' => 'paid-memberships-pro',
121
+ 'title' => __( 'Payment Settings', 'pmpro'),
122
+ 'href' => get_admin_url(NULL, '/admin.php?page=pmpro-paymentsettings') ) );
123
+
124
+ if(current_user_can('pmpro_emailsettings'))
125
+ $wp_admin_bar->add_menu( array(
126
+ 'id' => 'pmpro-email-settings',
127
+ 'parent' => 'paid-memberships-pro',
128
+ 'title' => __( 'Email Settings', 'pmpro'),
129
+ 'href' => get_admin_url(NULL, '/admin.php?page=pmpro-emailsettings') ) );
130
+
131
+ if(current_user_can('pmpro_advancedsettings'))
132
+ $wp_admin_bar->add_menu( array(
133
+ 'id' => 'pmpro-advanced-settings',
134
+ 'parent' => 'paid-memberships-pro',
135
+ 'title' => __( 'Advanced Settings', 'pmpro'),
136
+ 'href' => get_admin_url(NULL, '/admin.php?page=pmpro-advancedsettings') ) );
137
+
138
+ if(current_user_can('pmpro_addons'))
139
+ $wp_admin_bar->add_menu( array(
140
+ 'id' => 'pmpro-addons',
141
+ 'parent' => 'paid-memberships-pro',
142
+ 'title' => __( 'Add Ons', 'pmpro'),
143
+ 'href' => get_admin_url(NULL, '/admin.php?page=pmpro-addons') ) );
144
+
145
+ if(current_user_can('pmpro_memberslist'))
146
+ $wp_admin_bar->add_menu( array(
147
+ 'id' => 'pmpro-members-list',
148
+ 'parent' => 'paid-memberships-pro',
149
+ 'title' => __( 'Members List', 'pmpro'),
150
+ 'href' => get_admin_url(NULL, '/admin.php?page=pmpro-memberslist') ) );
151
+
152
+ if(current_user_can('pmpro_reports'))
153
+ $wp_admin_bar->add_menu( array(
154
+ 'id' => 'pmpro-reports',
155
+ 'parent' => 'paid-memberships-pro',
156
+ 'title' => __( 'Reports', 'pmpro'),
157
+ 'href' => get_admin_url(NULL, '/admin.php?page=pmpro-reports') ) );
158
+
159
+ if(current_user_can('pmpro_orders'))
160
+ $wp_admin_bar->add_menu( array(
161
+ 'id' => 'pmpro-orders',
162
+ 'parent' => 'paid-memberships-pro',
163
+ 'title' => __( 'Orders', 'pmpro'),
164
+ 'href' => get_admin_url(NULL, '/admin.php?page=pmpro-orders') ) );
165
+
166
+ if(current_user_can('pmpro_discountcodes'))
167
+ $wp_admin_bar->add_menu( array(
168
+ 'id' => 'pmpro-discount-codes',
169
+ 'parent' => 'paid-memberships-pro',
170
+ 'title' => __( 'Discount Codes', 'pmpro'),
171
+ 'href' => get_admin_url(NULL, '/admin.php?page=pmpro-discountcodes') ) );
172
+ }
173
+ add_action('admin_bar_menu', 'pmpro_admin_bar_menu', 1000);
174
+
175
+ /*
176
+ Functions to load pages from adminpages directory
177
+ */
178
+ function pmpro_reports()
179
+ {
180
+ require_once(PMPRO_DIR . "/adminpages/reports.php");
181
+ }
182
+
183
+ function pmpro_memberslist()
184
+ {
185
+ require_once(PMPRO_DIR . "/adminpages/memberslist.php");
186
+ }
187
+
188
+ function pmpro_discountcodes()
189
+ {
190
+ require_once(PMPRO_DIR . "/adminpages/discountcodes.php");
191
+ }
192
+
193
+ function pmpro_membershiplevels()
194
+ {
195
+ require_once(PMPRO_DIR . "/adminpages/membershiplevels.php");
196
+ }
197
+
198
+ function pmpro_pagesettings()
199
+ {
200
+ require_once(PMPRO_DIR . "/adminpages/pagesettings.php");
201
+ }
202
+
203
+ function pmpro_paymentsettings()
204
+ {
205
+ require_once(PMPRO_DIR . "/adminpages/paymentsettings.php");
206
+ }
207
+
208
+ function pmpro_emailsettings()
209
+ {
210
+ require_once(PMPRO_DIR . "/adminpages/emailsettings.php");
211
+ }
212
+
213
+ function pmpro_advancedsettings()
214
+ {
215
+ require_once(PMPRO_DIR . "/adminpages/advancedsettings.php");
216
+ }
217
+
218
+ function pmpro_addons()
219
+ {
220
+ require_once(PMPRO_DIR . "/adminpages/addons.php");
221
+ }
222
+
223
+ function pmpro_orders()
224
+ {
225
+ require_once(PMPRO_DIR . "/adminpages/orders.php");
226
+ }
includes/cleanup.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Clean things up when deletes happen, etc. (This stuff needs a better home.)
4
+ */
5
+ //deleting a user? remove their account info.
6
+ function pmpro_delete_user($user_id = NULL)
7
+ {
8
+ global $wpdb;
9
+
10
+ //changing their membership level to 0 will cancel any subscription and remove their membership level entry
11
+ //we don't remove the orders because it would affect reporting
12
+ if(pmpro_changeMembershipLevel(0, $user_id))
13
+ {
14
+ //okay
15
+ }
16
+ else
17
+ {
18
+ //okay, guessing they didn't have a level
19
+ }
20
+ }
21
+ add_action('delete_user', 'pmpro_delete_user');
22
+ add_action('wpmu_delete_user', 'pmpro_delete_user');
23
+
24
+ //deleting a category? remove any level associations
25
+ function pmpro_delete_category($cat_id = NULL)
26
+ {
27
+ global $wpdb;
28
+ $sqlQuery = "DELETE FROM $wpdb->pmpro_memberships_categories WHERE category_id = '" . $cat_id . "'";
29
+ $wpdb->query($sqlQuery);
30
+ }
31
+ add_action('delete_category', 'pmpro_delete_category');
32
+
33
+ //deleting a post? remove any level associations
34
+ function pmpro_delete_post($post_id = NULL)
35
+ {
36
+ global $wpdb;
37
+ $sqlQuery = "DELETE FROM $wpdb->pmpro_memberships_pages WHERE page_id = '" . $post_id . "'";
38
+ $wpdb->query($sqlQuery);
39
+ }
40
+ add_action('delete_post', 'pmpro_delete_post');
includes/content.php ADDED
@@ -0,0 +1,437 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Functions to detect member content and protect it.
4
+ */
5
+ function pmpro_has_membership_access($post_id = NULL, $user_id = NULL, $return_membership_levels = false)
6
+ {
7
+ global $post, $wpdb, $current_user;
8
+ //use globals if no values supplied
9
+ if(!$post_id)
10
+ $post_id = $post->ID;
11
+ if(!$user_id)
12
+ $user_id = $current_user->ID;
13
+
14
+ //no post, return true (changed from false in version 1.7.2)
15
+ if(!$post_id)
16
+ return true;
17
+
18
+ //if no post or current_user object, set them up
19
+ if(!empty($post->ID) && $post_id == $post->ID)
20
+ $mypost = $post;
21
+ else
22
+ $mypost = get_post($post_id);
23
+
24
+ if($user_id == $current_user->ID)
25
+ $myuser = $current_user;
26
+ else
27
+ $myuser = get_userdata($user_id);
28
+
29
+ //for these post types, we want to check the parent
30
+ if($mypost->post_type == "attachment" || $mypost->post_type == "revision")
31
+ {
32
+ $mypost = get_post($mypost->post_parent);
33
+ }
34
+
35
+ if($mypost->post_type == "post")
36
+ {
37
+ $post_categories = wp_get_post_categories($mypost->ID);
38
+
39
+ if(!$post_categories)
40
+ {
41
+ //just check for entries in the memberships_pages table
42
+ $sqlQuery = "SELECT m.id, m.name FROM $wpdb->pmpro_memberships_pages mp LEFT JOIN $wpdb->pmpro_membership_levels m ON mp.membership_id = m.id WHERE mp.page_id = '" . $mypost->ID . "'";
43
+ }
44
+ else
45
+ {
46
+ //are any of the post categories associated with membership levels? also check the memberships_pages table
47
+ $sqlQuery = "(SELECT m.id, m.name FROM $wpdb->pmpro_memberships_categories mc LEFT JOIN $wpdb->pmpro_membership_levels m ON mc.membership_id = m.id WHERE mc.category_id IN(" . implode(",", $post_categories) . ") AND m.id IS NOT NULL) UNION (SELECT m.id, m.name FROM $wpdb->pmpro_memberships_pages mp LEFT JOIN $wpdb->pmpro_membership_levels m ON mp.membership_id = m.id WHERE mp.page_id = '" . $mypost->ID . "')";
48
+ }
49
+ }
50
+ else
51
+ {
52
+ //are any membership levels associated with this page?
53
+ $sqlQuery = "SELECT m.id, m.name FROM $wpdb->pmpro_memberships_pages mp LEFT JOIN $wpdb->pmpro_membership_levels m ON mp.membership_id = m.id WHERE mp.page_id = '" . $mypost->ID . "'";
54
+ }
55
+
56
+
57
+ $post_membership_levels = $wpdb->get_results($sqlQuery);
58
+
59
+ $post_membership_levels_ids = array();
60
+ $post_membership_levels_names = array();
61
+
62
+ if(!$post_membership_levels)
63
+ {
64
+ $hasaccess = true;
65
+ }
66
+ else
67
+ {
68
+ //we need to see if the user has access
69
+ foreach($post_membership_levels as $level)
70
+ {
71
+ $post_membership_levels_ids[] = $level->id;
72
+ $post_membership_levels_names[] = $level->name;
73
+ }
74
+
75
+ //levels found. check if this is in a feed or if the current user is in at least one of those membership levels
76
+ if(is_feed())
77
+ {
78
+ //always block restricted feeds
79
+ $hasaccess = false;
80
+ }
81
+ elseif(!empty($myuser->ID))
82
+ {
83
+ $myuser->membership_level = pmpro_getMembershipLevelForUser($myuser->ID);
84
+ if(!empty($myuser->membership_level->ID) && in_array($myuser->membership_level->ID, $post_membership_levels_ids))
85
+ {
86
+ //the users membership id is one that will grant access
87
+ $hasaccess = true;
88
+ }
89
+ else
90
+ {
91
+ //user isn't a member of a level with access
92
+ $hasaccess = false;
93
+ }
94
+ }
95
+ else
96
+ {
97
+ //user is not logged in and this content requires membership
98
+ $hasaccess = false;
99
+ }
100
+ }
101
+
102
+ /*
103
+ Filters
104
+ The generic filter is run first. Then if there is a filter for this post type, that is run.
105
+ */
106
+ //general filter for all posts
107
+ $hasaccess = apply_filters("pmpro_has_membership_access_filter", $hasaccess, $mypost, $myuser, $post_membership_levels);
108
+ //filter for this post type
109
+ if(has_filter("pmpro_has_membership_access_filter_" . $mypost->post_type))
110
+ $hasaccess = apply_filters("pmpro_has_membership_access_filter_" . $mypost->post_type, $hasaccess, $mypost, $myuser, $post_membership_levels);
111
+
112
+ //return
113
+ if($return_membership_levels)
114
+ return array($hasaccess, $post_membership_levels_ids, $post_membership_levels_names);
115
+ else
116
+ return $hasaccess;
117
+ }
118
+
119
+ function pmpro_search_filter($query)
120
+ {
121
+ global $current_user, $wpdb, $pmpro_pages;
122
+
123
+ //hide pmpro pages from search results
124
+ if(!$query->is_admin && $query->is_search && empty($query->query['post_parent']))
125
+ {
126
+ $query->set('post__not_in', $pmpro_pages ); // id of page or post
127
+ }
128
+
129
+ //hide member pages from non-members (make sure they aren't hidden from members)
130
+ if(!$query->is_admin &&
131
+ !$query->is_singular &&
132
+ empty($query->query['post_parent']) &&
133
+ (
134
+ empty($query->query_vars['post_type']) ||
135
+ in_array($query->query_vars['post_type'], apply_filters('pmpro_search_filter_post_types', array("page", "post")))
136
+ )
137
+ )
138
+ {
139
+ //get page ids that are in my levels
140
+ $levels = pmpro_getMembershipLevelsForUser($current_user->ID);
141
+ $my_pages = array();
142
+
143
+ if($levels) {
144
+ foreach($levels as $key => $level) {
145
+ //get restricted posts for level
146
+ $sql = "SELECT page_id FROM $wpdb->pmpro_memberships_pages WHERE membership_id=" . $current_user->membership_level->ID;
147
+ $member_pages = $wpdb->get_col($sql);
148
+ $my_pages = array_unique(array_merge($my_pages, $member_pages));
149
+ }
150
+ }
151
+
152
+ //get hidden page ids
153
+ if(!empty($my_pages))
154
+ $sql = "SELECT page_id FROM $wpdb->pmpro_memberships_pages WHERE page_id NOT IN(" . implode(',', $my_pages) . ")";
155
+ else
156
+ $sql = "SELECT page_id FROM $wpdb->pmpro_memberships_pages";
157
+ $hidden_page_ids = array_values(array_unique($wpdb->get_col($sql)));
158
+
159
+ if($hidden_page_ids)
160
+ $query->set('post__not_in', $hidden_page_ids);
161
+
162
+ //get categories that are filtered by level, but not my level
163
+ global $pmpro_my_cats;
164
+ $pmpro_my_cats = array();
165
+
166
+ if($levels) {
167
+ foreach($levels as $key => $level) {
168
+ $member_cats = pmpro_getMembershipCategories($level->id);
169
+ $pmpro_my_cats = array_unique(array_merge($pmpro_my_cats, $member_cats));
170
+ }
171
+ }
172
+
173
+ //get hidden cats
174
+ if(!empty($pmpro_my_cats))
175
+ $sql = "SELECT category_id FROM $wpdb->pmpro_memberships_categories WHERE category_id NOT IN(" . implode(',', $pmpro_my_cats) . ")";
176
+ else
177
+ $sql = "SELECT category_id FROM $wpdb->pmpro_memberships_categories";
178
+
179
+ $hidden_cat_ids = array_values(array_unique($wpdb->get_col($sql)));
180
+
181
+ //make this work
182
+ if($hidden_cat_ids)
183
+ {
184
+ $query->set('category__not_in', $hidden_cat_ids);
185
+
186
+ //filter so posts in this member's categories are allowed
187
+ add_action('posts_where', 'pmpro_posts_where_unhide_cats');
188
+ }
189
+ }
190
+
191
+ return $query;
192
+ }
193
+ $filterqueries = pmpro_getOption("filterqueries");
194
+ if(!empty($filterqueries))
195
+ add_filter( 'pre_get_posts', 'pmpro_search_filter' );
196
+
197
+ /*
198
+ * Find taxonomy filters and make sure member categories are not hidden from members.
199
+ * @since 1.7.15
200
+ */
201
+ function pmpro_posts_where_unhide_cats($where)
202
+ {
203
+ global $pmpro_my_cats, $wpdb;
204
+
205
+ //if we have member cats, make sure they are allowed in taxonomy queries
206
+ if(!empty($where) && !empty($pmpro_my_cats))
207
+ {
208
+ $pattern = "/$wpdb->posts.ID NOT IN \(\s*SELECT object_id\s*FROM dev_term_relationships\s*WHERE term_taxonomy_id IN \((.*)\)\s*\)/";
209
+ $replacement = $wpdb->posts . '.ID NOT IN (
210
+ SELECT tr1.object_id
211
+ FROM ' . $wpdb->term_relationships . ' tr1
212
+ LEFT JOIN ' . $wpdb->term_relationships . ' tr2 ON tr1.object_id = tr2.object_id AND tr2.term_taxonomy_id IN(' . implode($pmpro_my_cats) . ')
213
+ WHERE tr1.term_taxonomy_id IN(${1}) AND tr2.term_taxonomy_id IS NULL ) ';
214
+ $where = preg_replace($pattern, $replacement, $where);
215
+ }
216
+
217
+ //remove filter for next query
218
+ remove_action('posts_where', 'pmpro_posts_where_unhide_cats');
219
+
220
+ return $where;
221
+ }
222
+
223
+ function pmpro_membership_content_filter($content, $skipcheck = false)
224
+ {
225
+ global $post, $current_user;
226
+
227
+ if(!$skipcheck)
228
+ {
229
+ $hasaccess = pmpro_has_membership_access(NULL, NULL, true);
230
+ if(is_array($hasaccess))
231
+ {
232
+ //returned an array to give us the membership level values
233
+ $post_membership_levels_ids = $hasaccess[1];
234
+ $post_membership_levels_names = $hasaccess[2];
235
+ $hasaccess = $hasaccess[0];
236
+ }
237
+ }
238
+
239
+ if($hasaccess)
240
+ {
241
+ //all good, return content
242
+ return $content;
243
+ }
244
+ else
245
+ {
246
+ //if show excerpts is set, return just the excerpt
247
+ if(pmpro_getOption("showexcerpts"))
248
+ {
249
+ //show excerpt
250
+ global $post;
251
+ if($post->post_excerpt)
252
+ {
253
+ //defined exerpt
254
+ $content = wpautop($post->post_excerpt);
255
+ }
256
+ elseif(strpos($content, "<span id=\"more-" . $post->ID . "\"></span>") !== false)
257
+ {
258
+ //more tag
259
+ $pos = strpos($content, "<span id=\"more-" . $post->ID . "\"></span>");
260
+ $content = wpautop(substr($content, 0, $pos));
261
+ }
262
+ elseif(strpos($content, 'class="more-link">') !== false)
263
+ {
264
+ //more link
265
+ $content = preg_replace("/\<a.*class\=\"more\-link\".*\>.*\<\/a\>/", "", $content);
266
+ }
267
+ else
268
+ {
269
+ //auto generated excerpt. pulled from wp_trim_excerpt
270
+ $content = strip_shortcodes( $content );
271
+ $content = str_replace(']]>', ']]&gt;', $content);
272
+ $content = strip_tags($content);
273
+ $excerpt_length = apply_filters('excerpt_length', 55);
274
+ $words = preg_split("/[\n\r\t ]+/", $content, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY);
275
+ if ( count($words) > $excerpt_length ) {
276
+ array_pop($words);
277
+ $content = implode(' ', $words);
278
+ $content = $content . "... ";
279
+ } else {
280
+ $content = implode(' ', $words) . "... ";
281
+ }
282
+
283
+ $content = wpautop($content);
284
+ }
285
+ }
286
+ else
287
+ {
288
+ //else hide everything
289
+ $content = "";
290
+ }
291
+
292
+ if(empty($post_membership_levels_ids))
293
+ $post_membership_levels_ids = array();
294
+
295
+ if(empty($post_membership_levels_names))
296
+ $post_membership_levels_names = array();
297
+
298
+ $pmpro_content_message_pre = '<div class="pmpro_content_message">';
299
+ $pmpro_content_message_post = '</div>';
300
+
301
+ $sr_search = array("!!levels!!", "!!referrer!!");
302
+ $sr_replace = array(pmpro_implodeToEnglish($post_membership_levels_names), $_SERVER['REQUEST_URI']);
303
+
304
+ //get the correct message to show at the bottom
305
+ if(is_feed())
306
+ {
307
+ $newcontent = apply_filters("pmpro_rss_text_filter", stripslashes(pmpro_getOption("rsstext")));
308
+ $content .= $pmpro_content_message_pre . str_replace($sr_search, $sr_replace, $newcontent) . $pmpro_content_message_post;
309
+ }
310
+ elseif($current_user->ID)
311
+ {
312
+ //not a member
313
+ $newcontent = apply_filters("pmpro_non_member_text_filter", stripslashes(pmpro_getOption("nonmembertext")));
314
+ $content .= $pmpro_content_message_pre . str_replace($sr_search, $sr_replace, $newcontent) . $pmpro_content_message_post;
315
+ }
316
+ else
317
+ {
318
+ //not logged in!
319
+ $newcontent = apply_filters("pmpro_not_logged_in_text_filter", stripslashes(pmpro_getOption("notloggedintext")));
320
+ $content .= $pmpro_content_message_pre . str_replace($sr_search, $sr_replace, $newcontent) . $pmpro_content_message_post;
321
+ }
322
+ }
323
+
324
+ return $content;
325
+ }
326
+ add_filter('the_content', 'pmpro_membership_content_filter', 5);
327
+ add_filter('the_content_rss', 'pmpro_membership_content_filter', 5);
328
+ add_filter('comment_text_rss', 'pmpro_membership_content_filter', 5);
329
+
330
+ /*
331
+ If the_excerpt is called, we want to disable the_content filters so the PMPro messages aren't added to the content before AND after the ecerpt.
332
+ */
333
+ function pmpro_membership_excerpt_filter($content, $skipcheck = false)
334
+ {
335
+ remove_filter('the_content', 'pmpro_membership_content_filter', 5);
336
+ $content = pmpro_membership_content_filter($content, $skipcheck);
337
+ add_filter('the_content', 'pmpro_membership_content_filter', 5);
338
+
339
+ return $content;
340
+ }
341
+ function pmpro_membership_get_excerpt_filter_start($content, $skipcheck = false)
342
+ {
343
+ remove_filter('the_content', 'pmpro_membership_content_filter', 5);
344
+ return $content;
345
+ }
346
+ function pmpro_membership_get_excerpt_filter_end($content, $skipcheck = false)
347
+ {
348
+ add_filter('the_content', 'pmpro_membership_content_filter', 5);
349
+ return $content;
350
+ }
351
+ add_filter('the_excerpt', 'pmpro_membership_excerpt_filter', 15);
352
+ add_filter('get_the_excerpt', 'pmpro_membership_get_excerpt_filter_start', 1);
353
+ add_filter('get_the_excerpt', 'pmpro_membership_get_excerpt_filter_end', 100);
354
+
355
+ function pmpro_comments_filter($comments, $post_id = NULL)
356
+ {
357
+ global $post, $wpdb, $current_user;
358
+ if(!$post_id)
359
+ $post_id = $post->ID;
360
+
361
+ if(!$comments)
362
+ return $comments; //if they are closed anyway, we don't need to check
363
+
364
+ global $post, $current_user;
365
+
366
+ $hasaccess = pmpro_has_membership_access(NULL, NULL, true);
367
+ if(is_array($hasaccess))
368
+ {
369
+ //returned an array to give us the membership level values
370
+ $post_membership_levels_ids = $hasaccess[1];
371
+ $post_membership_levels_names = $hasaccess[2];
372
+ $hasaccess = $hasaccess[0];
373
+ }
374
+
375
+ if($hasaccess)
376
+ {
377
+ //all good, return content
378
+ return $comments;
379
+ }
380
+ else
381
+ {
382
+ if(!$post_membership_levels_ids)
383
+ $post_membership_levels_ids = array();
384
+
385
+ if(!$post_membership_levels_names)
386
+ $post_membership_levels_names = array();
387
+
388
+ //get the correct message
389
+ if(is_feed())
390
+ {
391
+ if(is_array($comments))
392
+ return array();
393
+ else
394
+ return false;
395
+ }
396
+ elseif($current_user->ID)
397
+ {
398
+ //not a member
399
+ if(is_array($comments))
400
+ return array();
401
+ else
402
+ return false;
403
+ }
404
+ else
405
+ {
406
+ //not logged in!
407
+ if(is_array($comments))
408
+ return array();
409
+ else
410
+ return false;
411
+ }
412
+ }
413
+
414
+ return $comments;
415
+ }
416
+ add_filter("comments_array", "pmpro_comments_filter");
417
+ add_filter("comments_open", "pmpro_comments_filter");
418
+
419
+ //keep non-members from getting to certain pages (attachments, etc)
420
+ function pmpro_hide_pages_redirect()
421
+ {
422
+ global $post;
423
+
424
+ if(!is_admin() && !empty($post->ID))
425
+ {
426
+ if($post->post_type == "attachment")
427
+ {
428
+ //check if the user has access to the parent
429
+ if(!pmpro_has_membership_access($post->ID))
430
+ {
431
+ wp_redirect(pmpro_url("levels"));
432
+ exit;
433
+ }
434
+ }
435
+ }
436
+ }
437
+ add_action('wp', 'pmpro_hide_pages_redirect');
includes/countries.php ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //thanks JigoShop
3
+ global $pmpro_countries, $pmpro_default_country;
4
+ $pmpro_default_country = apply_filters("pmpro_default_country", "US");
5
+
6
+ $pmpro_countries = array(
7
+ 'AD' => 'Andorra',
8
+ 'AE' => 'United Arab Emirates',
9
+ 'AF' => 'Afghanistan',
10
+ 'AG' => 'Antigua and Barbuda',
11
+ 'AI' => 'Anguilla',
12
+ 'AL' => 'Albania',
13
+ 'AM' => 'Armenia',
14
+ 'AN' => 'Netherlands Antilles',
15
+ 'AO' => 'Angola',
16
+ 'AQ' => 'Antarctica',
17
+ 'AR' => 'Argentina',
18
+ 'AS' => 'American Samoa',
19
+ 'AT' => 'Austria',
20
+ 'AU' => 'Australia',
21
+ 'AW' => 'Aruba',
22
+ 'AX' => 'Aland Islands',
23
+ 'AZ' => 'Azerbaijan',
24
+ 'BA' => 'Bosnia and Herzegovina',
25
+ 'BB' => 'Barbados',
26
+ 'BD' => 'Bangladesh',
27
+ 'BE' => 'Belgium',
28
+ 'BF' => 'Burkina Faso',
29
+ 'BG' => 'Bulgaria',
30
+ 'BH' => 'Bahrain',
31
+ 'BI' => 'Burundi',
32
+ 'BJ' => 'Benin',
33
+ 'BL' => 'Saint Barthelemy',
34
+ 'BM' => 'Bermuda',
35
+ 'BN' => 'Brunei',
36
+ 'BO' => 'Bolivia',
37
+ 'BR' => 'Brazil',
38
+ 'BS' => 'Bahamas',
39
+ 'BT' => 'Bhutan',
40
+ 'BV' => 'Bouvet Island',
41
+ 'BW' => 'Botswana',
42
+ 'BY' => 'Belarus',
43
+ 'BZ' => 'Belize',
44
+ 'CA' => 'Canada',
45
+ 'CC' => 'Cocos (Keeling) Islands',
46
+ 'CD' => 'Congo (Kinshasa)',
47
+ 'CF' => 'Central African Republic',
48
+ 'CG' => 'Congo (Brazzaville)',
49
+ 'CH' => 'Switzerland',
50
+ 'CI' => 'Ivory Coast',
51
+ 'CK' => 'Cook Islands',
52
+ 'CL' => 'Chile',
53
+ 'CM' => 'Cameroon',
54
+ 'CN' => 'China',
55
+ 'CO' => 'Colombia',
56
+ 'CR' => 'Costa Rica',
57
+ 'CU' => 'Cuba',
58
+ 'CV' => 'Cape Verde',
59
+ 'CX' => 'Christmas Island',
60
+ 'CY' => 'Cyprus',
61
+ 'CZ' => 'Czech Republic',
62
+ 'DE' => 'Germany',
63
+ 'DJ' => 'Djibouti',
64
+ 'DK' => 'Denmark',
65
+ 'DM' => 'Dominica',
66
+ 'DO' => 'Dominican Republic',
67
+ 'DZ' => 'Algeria',
68
+ 'EC' => 'Ecuador',
69
+ 'EE' => 'Estonia',
70
+ 'EG' => 'Egypt',
71
+ 'EH' => 'Western Sahara',
72
+ 'ER' => 'Eritrea',
73
+ 'ES' => 'Spain',
74
+ 'ET' => 'Ethiopia',
75
+ 'FI' => 'Finland',
76
+ 'FJ' => 'Fiji',
77
+ 'FK' => 'Falkland Islands',
78
+ 'FM' => 'Micronesia',
79
+ 'FO' => 'Faroe Islands',
80
+ 'FR' => 'France',
81
+ 'GA' => 'Gabon',
82
+ 'GB' => 'United Kingdom',
83
+ 'GD' => 'Grenada',
84
+ 'GE' => 'Georgia',
85
+ 'GF' => 'French Guiana',
86
+ 'GG' => 'Guernsey',
87
+ 'GH' => 'Ghana',
88
+ 'GI' => 'Gibraltar',
89
+ 'GL' => 'Greenland',
90
+ 'GM' => 'Gambia',
91
+ 'GN' => 'Guinea',
92
+ 'GP' => 'Guadeloupe',
93
+ 'GQ' => 'Equatorial Guinea',
94
+ 'GR' => 'Greece',
95
+ 'GS' => 'South Georgia and the South Sandwich Islands',
96
+ 'GT' => 'Guatemala',
97
+ 'GU' => 'Guam',
98
+ 'GW' => 'Guinea-Bissau',
99
+ 'GY' => 'Guyana',
100
+ 'HK' => 'Hong Kong S.A.R., China',
101
+ 'HM' => 'Heard Island and McDonald Islands',
102
+ 'HN' => 'Honduras',
103
+ 'HR' => 'Croatia',
104
+ 'HT' => 'Haiti',
105
+ 'HU' => 'Hungary',
106
+ 'ID' => 'Indonesia',
107
+ 'IE' => 'Ireland',
108
+ 'IL' => 'Israel',
109
+ 'IM' => 'Isle of Man',
110
+ 'IN' => 'India',
111
+ 'IO' => 'British Indian Ocean Territory',
112
+ 'IQ' => 'Iraq',
113
+ 'IR' => 'Iran',
114
+ 'IS' => 'Iceland',
115
+ 'IT' => 'Italy',
116
+ 'JE' => 'Jersey',
117
+ 'JM' => 'Jamaica',
118
+ 'JO' => 'Jordan',
119
+ 'JP' => 'Japan',
120
+ 'KE' => 'Kenya',
121
+ 'KG' => 'Kyrgyzstan',
122
+ 'KH' => 'Cambodia',
123
+ 'KI' => 'Kiribati',
124
+ 'KM' => 'Comoros',
125
+ 'KN' => 'Saint Kitts and Nevis',
126
+ 'KP' => 'North Korea',
127
+ 'KR' => 'South Korea',
128
+ 'KW' => 'Kuwait',
129
+ 'KY' => 'Cayman Islands',
130
+ 'KZ' => 'Kazakhstan',
131
+ 'LA' => 'Laos',
132
+ 'LB' => 'Lebanon',
133
+ 'LC' => 'Saint Lucia',
134
+ 'LI' => 'Liechtenstein',
135
+ 'LK' => 'Sri Lanka',
136
+ 'LR' => 'Liberia',
137
+ 'LS' => 'Lesotho',
138
+ 'LT' => 'Lithuania',
139
+ 'LU' => 'Luxembourg',
140
+ 'LV' => 'Latvia',
141
+ 'LY' => 'Libya',
142
+ 'MA' => 'Morocco',
143
+ 'MC' => 'Monaco',
144
+ 'MD' => 'Moldova',
145
+ 'ME' => 'Montenegro',
146
+ 'MF' => 'Saint Martin (French part)',
147
+ 'MG' => 'Madagascar',
148
+ 'MH' => 'Marshall Islands',
149
+ 'MK' => 'Macedonia',
150
+ 'ML' => 'Mali',
151
+ 'MM' => 'Myanmar',
152
+ 'MN' => 'Mongolia',
153
+ 'MO' => 'Macao S.A.R., China',
154
+ 'MP' => 'Northern Mariana Islands',
155
+ 'MQ' => 'Martinique',
156
+ 'MR' => 'Mauritania',
157
+ 'MS' => 'Montserrat',
158
+ 'MT' => 'Malta',
159
+ 'MU' => 'Mauritius',
160
+ 'MV' => 'Maldives',
161
+ 'MW' => 'Malawi',
162
+ 'MX' => 'Mexico',
163
+ 'MY' => 'Malaysia',
164
+ 'MZ' => 'Mozambique',
165
+ 'NA' => 'Namibia',
166
+ 'NC' => 'New Caledonia',
167
+ 'NE' => 'Niger',
168
+ 'NF' => 'Norfolk Island',
169
+ 'NG' => 'Nigeria',
170
+ 'NI' => 'Nicaragua',
171
+ 'NL' => 'Netherlands',
172
+ 'NO' => 'Norway',
173
+ 'NP' => 'Nepal',
174
+ 'NR' => 'Nauru',
175
+ 'NU' => 'Niue',
176
+ 'NZ' => 'New Zealand',
177
+ 'OM' => 'Oman',
178
+ 'PA' => 'Panama',
179
+ 'PE' => 'Peru',
180
+ 'PF' => 'French Polynesia',
181
+ 'PG' => 'Papua New Guinea',
182
+ 'PH' => 'Philippines',
183
+ 'PK' => 'Pakistan',
184
+ 'PL' => 'Poland',
185
+ 'PM' => 'Saint Pierre and Miquelon',
186
+ 'PN' => 'Pitcairn',
187
+ 'PR' => 'Puerto Rico',
188
+ 'PS' => 'Palestinian Territory',
189
+ 'PT' => 'Portugal',
190
+ 'PW' => 'Palau',
191
+ 'PY' => 'Paraguay',
192
+ 'QA' => 'Qatar',
193
+ 'RE' => 'Reunion',
194
+ 'RO' => 'Romania',
195
+ 'RS' => 'Serbia',
196
+ 'RU' => 'Russia',
197
+ 'RW' => 'Rwanda',
198
+ 'SA' => 'Saudi Arabia',
199
+ 'SB' => 'Solomon Islands',
200
+ 'SC' => 'Seychelles',
201
+ 'SD' => 'Sudan',
202
+ 'SE' => 'Sweden',
203
+ 'SG' => 'Singapore',
204
+ 'SH' => 'Saint Helena',
205
+ 'SI' => 'Slovenia',
206
+ 'SJ' => 'Svalbard and Jan Mayen',
207
+ 'SK' => 'Slovakia',
208
+ 'SL' => 'Sierra Leone',
209
+ 'SM' => 'San Marino',
210
+ 'SN' => 'Senegal',
211
+ 'SO' => 'Somalia',
212
+ 'SR' => 'Suriname',
213
+ 'ST' => 'Sao Tome and Principe',
214
+ 'SV' => 'El Salvador',
215
+ 'SY' => 'Syria',
216
+ 'SZ' => 'Swaziland',
217
+ 'TC' => 'Turks and Caicos Islands',
218
+ 'TD' => 'Chad',
219
+ 'TF' => 'French Southern Territories',
220
+ 'TG' => 'Togo',
221
+ 'TH' => 'Thailand',
222
+ 'TJ' => 'Tajikistan',
223
+ 'TK' => 'Tokelau',
224
+ 'TL' => 'Timor-Leste',
225
+ 'TM' => 'Turkmenistan',
226
+ 'TN' => 'Tunisia',
227
+ 'TO' => 'Tonga',
228
+ 'TR' => 'Turkey',
229
+ 'TT' => 'Trinidad and Tobago',
230
+ 'TV' => 'Tuvalu',
231
+ 'TW' => 'Taiwan',
232
+ 'TZ' => 'Tanzania',
233
+ 'UA' => 'Ukraine',
234
+ 'UG' => 'Uganda',
235
+ 'UM' => 'United States Minor Outlying Islands',
236
+ 'US' => 'United States',
237
+ 'UY' => 'Uruguay',
238
+ 'UZ' => 'Uzbekistan',
239
+ 'VA' => 'Vatican',
240
+ 'VC' => 'Saint Vincent and the Grenadines',
241
+ 'VE' => 'Venezuela',
242
+ 'VG' => 'British Virgin Islands',
243
+ 'VI' => 'U.S. Virgin Islands',
244
+ 'VN' => 'Vietnam',
245
+ 'VU' => 'Vanuatu',
246
+ 'WF' => 'Wallis and Futuna',
247
+ 'WS' => 'Samoa',
248
+ 'YE' => 'Yemen',
249
+ 'YT' => 'Mayotte',
250
+ 'ZA' => 'South Africa',
251
+ 'ZM' => 'Zambia',
252
+ 'ZW' => 'Zimbabwe',
253
+ 'USAF' => 'US Armed Forces' ,
254
+ 'VE' => 'Venezuela',
255
+ );
256
+
257
+ asort($pmpro_countries);
258
+
259
+ $pmpro_countries = apply_filters("pmpro_countries", $pmpro_countries);
includes/currencies.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //thanks jigoshop
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'),
15
+ 'symbol' => '&pound;',
16
+ 'position' => 'left'
17
+ ),
18
+ 'AUD' => __('Australian Dollars (&#36;)', 'pmpro'),
19
+ 'BRL' => array(
20
+ 'name' => __('Brazilian Real (R&#36;)', 'pmpro'),
21
+ 'symbol' => 'R&#36;',
22
+ 'position' => 'left'
23
+ ),
24
+ 'CAD' => __('Canadian Dollars (&#36;)', 'pmpro'),
25
+ 'CNY' => __('Chinese Yuan', 'pmpro'),
26
+ 'CZK' => __('Czech Koruna', 'pmpro'),
27
+ 'DKK' => __('Danish Krone', 'pmpro'),
28
+ 'HKD' => __('Hong Kong Dollar (&#36;)', 'pmpro'),
29
+ 'HUF' => __('Hungarian Forint', 'pmpro'),
30
+ 'INR' => __('Indian Rupee', 'pmpro'),
31
+ 'IDR' => __('Indonesia Rupiah', 'pmpro'),
32
+ 'ILS' => __('Israeli Shekel', 'pmpro'),
33
+ 'JPY' => array(
34
+ 'name' => __('Japanese Yen (&yen;)', 'pmpro'),
35
+ 'symbol' => '&yen;',
36
+ 'position' => 'right'
37
+ ),
38
+ 'MYR' => __('Malaysian Ringgits', 'pmpro'),
39
+ 'MXN' => __('Mexican Peso (&#36;)', 'pmpro'),
40
+ 'NZD' => __('New Zealand Dollar (&#36;)', 'pmpro'),
41
+ 'NOK' => __('Norwegian Krone', 'pmpro'),
42
+ 'PHP' => __('Philippine Pesos', 'pmpro'),
43
+ 'PLN' => __('Polish Zloty', 'pmpro'),
44
+ 'SGD' => array(
45
+ 'name' => __('Singapore Dollar (&#36;)', 'pmpro'),
46
+ 'symbol' => '&#36;',
47
+ 'position' => 'right'
48
+ ),
49
+ 'ZAR' => __('South African Rand', 'pmpro'),
50
+ 'KRW' => __('South Korean Won', 'pmpro'),
51
+ 'SEK' => __('Swedish Krona', 'pmpro'),
52
+ 'CHF' => __('Swiss Franc', 'pmpro'),
53
+ 'TWD' => __('Taiwan New Dollars', 'pmpro'),
54
+ 'THB' => __('Thai Baht', 'pmpro'),
55
+ 'TRY' => __('Turkish Lira', 'pmpro'),
56
+ 'VND' => __('Vietnamese Dong', 'pmpro')
57
+ );
58
+
59
+ $pmpro_currencies = apply_filters("pmpro_currencies", $pmpro_currencies);
60
+
61
+ //stripe only supports a few (not using this anymore since 1.7.4)
62
+ global $pmpro_stripe_currencies;
63
+ $pmpro_stripe_currencies = array(
64
+ 'USD' => __('US Dollars (&#36;)', 'pmpro'),
65
+ 'CAD' => __('Canadian Dollars (&#36;)', 'pmpro'),
66
+ 'GBP' => __('Pounds Sterling (&pound;)', 'pmpro'),
67
+ 'EUR' => __('Euros (&euro;)', 'pmpro')
68
+ );
69
+ ?>
includes/email.php ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Nicer default emails
4
+ */
5
+ function pmpro_wp_mail_from_name($from_name)
6
+ {
7
+ $default_from_name = 'WordPress';
8
+
9
+ //make sure it's the default from name
10
+ if($from_name == $default_from_name)
11
+ {
12
+ $pmpro_from_name = pmpro_getOption("from_name");
13
+ if ($pmpro_from_name)
14
+ $from_name = $pmpro_from_name;
15
+ }
16
+
17
+ return $from_name;
18
+ }
19
+ function pmpro_wp_mail_from($from_email)
20
+ {
21
+ // default from email wordpress@sitename
22
+ $sitename = strtolower( $_SERVER['SERVER_NAME'] );
23
+ if ( substr( $sitename, 0, 4 ) == 'www.' ) {
24
+ $sitename = substr( $sitename, 4 );
25
+ }
26
+ $default_from_email = 'wordpress@' . $sitename;
27
+
28
+ //make sure it's the default email address
29
+ if($from_email == $default_from_email)
30
+ {
31
+ $pmpro_from_email = pmpro_getOption("from_email");
32
+ if ($pmpro_from_email && is_email( $pmpro_from_email ) )
33
+ $from_email = $pmpro_from_email;
34
+ }
35
+
36
+ return $from_email;
37
+ }
38
+
39
+ $only_filter_pmpro_emails = pmpro_getOption("only_filter_pmpro_emails");
40
+ if($only_filter_pmpro_emails)
41
+ {
42
+ add_filter('pmpro_email_sender_name', 'pmpro_wp_mail_from_name');
43
+ add_filter('pmpro_email_sender', 'pmpro_wp_mail_from');
44
+ }
45
+ else
46
+ {
47
+ add_filter('wp_mail_from_name', 'pmpro_wp_mail_from_name');
48
+ add_filter('wp_mail_from', 'pmpro_wp_mail_from');
49
+ }
50
+
51
+ /*
52
+ If the $email_member_notification option is empty, disable the wp_new_user_notification email at checkout.
53
+ */
54
+ $email_member_notification = pmpro_getOption("email_member_notification");
55
+ if(empty($email_member_notification))
56
+ add_filter("pmpro_wp_new_user_notification", "__return_false", 0);
57
+
58
+ /*
59
+ Adds template files and changes content type to html if using PHPMailer directly.
60
+ */
61
+ function pmpro_send_html( $phpmailer ) {
62
+
63
+ //check if we should wpautop later
64
+ if($phpmailer->Body == strip_tags($phpmailer->Body))
65
+ $wpautop = true;
66
+ else
67
+ $wpautop = false;
68
+
69
+ // Set the original plain text message
70
+ $phpmailer->AltBody = wp_specialchars_decode($phpmailer->Body, ENT_QUOTES);
71
+ // Clean < and > around text links in WP 3.1
72
+ $phpmailer->Body = preg_replace('#<(http://[^*]+)>#', '$1', $phpmailer->Body);
73
+ // Convert line breaks & make links clickable
74
+ $phpmailer->Body = make_clickable ($phpmailer->Body);
75
+
76
+ // Add header to message if found
77
+ if(file_exists(get_stylesheet_directory() . "/email_header.html"))
78
+ $phpmailer->Body = file_get_contents(get_stylesheet_directory() . "/email_header.html") . "\n" . $phpmailer->Body;
79
+ elseif(file_exists(get_template_directory() . "/email_header.html"))
80
+ $phpmailer->Body = file_get_contents(get_template_directory() . "/email_header.html") . "\n" . $phpmailer->Body;
81
+
82
+ // Add footer to message if found
83
+ if(file_exists(get_stylesheet_directory() . "/email_footer.html"))
84
+ $phpmailer->Body = $phpmailer->Body . "\n" . file_get_contents(get_stylesheet_directory() . "/email_footer.html");
85
+ elseif(file_exists(get_template_directory() . "/email_footer.html"))
86
+ $phpmailer->Body = $phpmailer->Body . "\n" . file_get_contents(get_template_directory() . "/email_footer.html");
87
+
88
+ // Replace variables in email
89
+ global $current_user;
90
+ $data = array(
91
+ "name" => $current_user->display_name,
92
+ "sitename" => get_option("blogname"),
93
+ "login_link" => pmpro_url("account"),
94
+ "display_name" => $current_user->display_name,
95
+ "user_email" => $current_user->user_email,
96
+ "subject" => $phpmailer->Subject
97
+ );
98
+ foreach($data as $key => $value)
99
+ {
100
+ $phpmailer->Body = str_replace("!!" . $key . "!!", $value, $phpmailer->Body);
101
+ }
102
+
103
+ if($wpautop)
104
+ $phpmailer->Body = wpautop($phpmailer->Body);
105
+
106
+ do_action("pmpro_after_phpmailer_init", $phpmailer);
107
+ do_action("pmpro_after_pmpmailer_init", $phpmailer); //typo left in for backwards compatibility
108
+ }
109
+
110
+ function pmpro_wp_mail_content_type( $content_type ) {
111
+ add_action('phpmailer_init', 'pmpro_send_html');
112
+
113
+ //change to html if not already
114
+ if( $content_type == 'text/plain')
115
+ {
116
+ $content_type = 'text/html';
117
+ }
118
+ return $content_type;
119
+ }
120
+ add_filter('wp_mail_content_type', 'pmpro_wp_mail_content_type');
includes/filters.php ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ This file was added in version 1.5.5 of the plugin. This file is meant to store various hacks, filters, and actions that were originally developed outside of the PMPro core and brought in later... or just things that are cleaner/easier to impement via hooks and filters.
4
+ */
5
+
6
+ /*
7
+ If checking out for the same level, add remaining days to the enddate.
8
+ Pulled in from: https://gist.github.com/3678054
9
+ */
10
+ function pmpro_checkout_level_extend_memberships($level)
11
+ {
12
+ global $pmpro_msg, $pmpro_msgt;
13
+
14
+ //does this level expire? are they an existing user of this level?
15
+ if(!empty($level) && !empty($level->expiration_number) && pmpro_hasMembershipLevel($level->id))
16
+ {
17
+ //get the current enddate of their membership
18
+ global $current_user;
19
+ $expiration_date = $current_user->membership_level->enddate;
20
+
21
+ //calculate days left
22
+ $todays_date = current_time('timestamp');
23
+ $time_left = $expiration_date - $todays_date;
24
+
25
+ //time left?
26
+ if($time_left > 0)
27
+ {
28
+ //convert to days and add to the expiration date (assumes expiration was 1 year)
29
+ $days_left = floor($time_left/(60*60*24));
30
+
31
+ //figure out days based on period
32
+ if($level->expiration_period == "Day")
33
+ $total_days = $days_left + $level->expiration_number;
34
+ elseif($level->expiration_period == "Week")
35
+ $total_days = $days_left + $level->expiration_number * 7;
36
+ elseif($level->expiration_period == "Month")
37
+ $total_days = $days_left + $level->expiration_number * 30;
38
+ elseif($level->expiration_period == "Year")
39
+ $total_days = $days_left + $level->expiration_number * 365;
40
+
41
+ //update number and period
42
+ $level->expiration_number = $total_days;
43
+ $level->expiration_period = "Day";
44
+ }
45
+ }
46
+
47
+ return $level;
48
+ }
49
+ add_filter("pmpro_checkout_level", "pmpro_checkout_level_extend_memberships");
50
+ /*
51
+ Same thing as above but when processed by the ipnhandler for PayPal standard.
52
+ */
53
+ function pmpro_ipnhandler_level_extend_memberships($level, $user_id)
54
+ {
55
+ global $pmpro_msg, $pmpro_msgt;
56
+
57
+ //does this level expire? are they an existing user of this level?
58
+ if(!empty($level) && !empty($level->expiration_number) && pmpro_hasMembershipLevel($level->id, $user_id))
59
+ {
60
+ //get the current enddate of their membership
61
+ $user_level = pmpro_getMembershipLevelForUser($user_id);
62
+ $expiration_date = $user_level->enddate;
63
+
64
+ //calculate days left
65
+ $todays_date = current_time('timestamp');
66
+ $time_left = $expiration_date - $todays_date;
67
+
68
+ //time left?
69
+ if($time_left > 0)
70
+ {
71
+ //convert to days and add to the expiration date (assumes expiration was 1 year)
72
+ $days_left = floor($time_left/(60*60*24));
73
+
74
+ //figure out days based on period
75
+ if($level->expiration_period == "Day")
76
+ $total_days = $days_left + $level->expiration_number;
77
+ elseif($level->expiration_period == "Week")
78
+ $total_days = $days_left + $level->expiration_number * 7;
79
+ elseif($level->expiration_period == "Month")
80
+ $total_days = $days_left + $level->expiration_number * 30;
81
+ elseif($level->expiration_period == "Year")
82
+ $total_days = $days_left + $level->expiration_number * 365;
83
+
84
+ //update number and period
85
+ $level->expiration_number = $total_days;
86
+ $level->expiration_period = "Day";
87
+ }
88
+ }
89
+
90
+ return $level;
91
+ }
92
+ add_filter("pmpro_ipnhandler_level", "pmpro_ipnhandler_level_extend_memberships", 10, 2);
93
+
94
+ /*
95
+ If checking out for the same level, keep your old startdate.
96
+ Added with 1.5.5
97
+ */
98
+ function pmpro_checkout_start_date_keep_startdate($startdate, $user_id, $level)
99
+ {
100
+ if(pmpro_hasMembershipLevel($level->id, $user_id))
101
+ {
102
+ global $wpdb;
103
+ $sqlQuery = "SELECT startdate FROM $wpdb->pmpro_memberships_users WHERE user_id = '" . esc_sql($user_id) . "' AND membership_id = '" . esc_sql($level->id) . "' AND status = 'active' ORDER BY id DESC LIMIT 1";
104
+ $old_startdate = $wpdb->get_var($sqlQuery);
105
+
106
+ if(!empty($old_startdate))
107
+ $startdate = "'" . $old_startdate . "'";
108
+ }
109
+
110
+ return $startdate;
111
+ }
112
+ add_filter("pmpro_checkout_start_date", "pmpro_checkout_start_date_keep_startdate", 10, 3);
113
+
114
+ /*
115
+ Stripe Lite Pulled into Core Plugin
116
+ */
117
+ //Stripe Lite, Set the Globals/etc
118
+ $stripe_billingaddress = pmpro_getOption("stripe_billingaddress");
119
+ if(empty($stripe_billingaddress))
120
+ {
121
+ global $pmpro_stripe_lite;
122
+ $pmpro_stripe_lite = true;
123
+ add_filter("pmpro_stripe_lite", "__return_true");
124
+ add_filter("pmpro_required_billing_fields", "pmpro_required_billing_fields_stripe_lite");
125
+ }
126
+
127
+ //Stripe Lite, Don't Require Billing Fields
128
+ function pmpro_required_billing_fields_stripe_lite($fields)
129
+ {
130
+ global $gateway;
131
+
132
+ //ignore if not using stripe
133
+ if($gateway != "stripe")
134
+ return $fields;
135
+
136
+ //some fields to remove
137
+ $remove = array('bfirstname', 'blastname', 'baddress1', 'bcity', 'bstate', 'bzipcode', 'bphone', 'bcountry', 'CardType');
138
+
139
+ //if a user is logged in, don't require bemail either
140
+ global $current_user;
141
+ if(!empty($current_user->user_email))
142
+ $remove[] = 'bemail';
143
+
144
+ //remove the fields
145
+ foreach($remove as $field)
146
+ unset($fields[$field]);
147
+
148
+ //ship it!
149
+ return $fields;
150
+ }
includes/functions.php CHANGED
@@ -1,762 +1,1795 @@
1
- <?php
2
- if(!function_exists("sornot"))
3
- {
4
- function sornot($t, $n)
5
- {
6
- if($n == 1)
7
- return $t;
8
- else
9
- return $t . "s";
10
- }
11
- }
12
-
13
- //from: http://stackoverflow.com/questions/5266945/wordpress-how-detect-if-current-page-is-the-login-page/5892694#5892694
14
- function pmpro_is_login_page() {
15
- return in_array($GLOBALS['pagenow'], array('wp-login.php', 'wp-register.php'));
16
- }
17
-
18
- //thanks: http://wordpress.org/support/topic/is_plugin_active
19
- function pmpro_is_plugin_active( $plugin ) {
20
- return in_array( $plugin, (array) get_option( 'active_plugins', array() ) );
21
- }
22
-
23
- //scraping - override n if you have more than 1 group of matches and don't want the first group
24
- function pmpro_getMatches($p, $s, $firstvalue = FALSE, $n = 1)
25
- {
26
- $ok = preg_match_all($p, $s, $matches);
27
-
28
- if(!$ok)
29
- return false;
30
- else
31
- {
32
- if($firstvalue)
33
- return $matches[$n][0];
34
- else
35
- return $matches[$n];
36
- }
37
- }
38
-
39
- function pmpro_br2nl($text, $tags = "br")
40
- {
41
- if(!is_array($tags))
42
- $tags = explode(" ", $tags);
43
-
44
- foreach($tags as $tag)
45
- {
46
- $text = eregi_replace("<" . $tag . "[^>]*>", "\n", $text);
47
- $text = eregi_replace("</" . $tag . "[^>]*>", "\n", $text);
48
- }
49
-
50
- return($text);
51
- }
52
-
53
- function pmpro_getOption($s)
54
- {
55
- if($_REQUEST[$s])
56
- return $_REQUEST[$s];
57
- elseif(get_option("pmpro_" . $s))
58
- return get_option("pmpro_" . $s);
59
- else
60
- return "";
61
- }
62
-
63
- function pmpro_setOption($s, $v = NULL)
64
- {
65
- //no value is given, set v to the request var
66
- if($v === NULL)
67
- $v = $_REQUEST[$s];
68
-
69
- if(is_array($v))
70
- $v = implode(",", $v);
71
-
72
- return update_option("pmpro_" . $s, $v);
73
- }
74
-
75
- function pmpro_get_slug($post_id)
76
- {
77
- global $pmpro_slugs, $wpdb;
78
- if(!$pmpro_slugs[$post_id])
79
- $pmpro_slugs[$post_id] = $wpdb->get_var("SELECT post_name FROM $wpdb->posts WHERE ID = '" . $post_id . "' LIMIT 1");
80
-
81
- return $pmpro_slugs[$post_id];
82
- }
83
-
84
- function pmpro_url($page = NULL, $querystring = "", $scheme = NULL)
85
- {
86
- global $besecure;
87
- $besecure = apply_filters("besecure", $besecure);
88
-
89
- if(!$scheme && $besecure)
90
- $scheme = "https";
91
- elseif(!$scheme)
92
- $scheme = "http";
93
-
94
- if(!$page)
95
- $page = "levels";
96
-
97
- global $pmpro_pages;
98
-
99
- //? vs &
100
- if(strpos(get_permalink($pmpro_pages[$page]), "?"))
101
- return home_url(str_replace(home_url(), "", get_permalink($pmpro_pages[$page])) . str_replace("?", "&", $querystring), $scheme);
102
- else
103
- return home_url(str_replace(home_url(), "", get_permalink($pmpro_pages[$page])) . $querystring, $scheme);
104
- }
105
-
106
- function pmpro_isLevelFree(&$level)
107
- {
108
- if($level->initial_payment <= 0 && $level->billing_amount <= 0 && $level->trial_amount <= 0)
109
- return true;
110
- else
111
- return false;
112
- }
113
-
114
- function pmpro_isLevelRecurring(&$level)
115
- {
116
- if($level->billing_amount > 0 || $level->trial_amount > 0)
117
- return true;
118
- else
119
- return false;
120
- }
121
-
122
- function pmpro_isLevelTrial(&$level)
123
- {
124
- if($level->trial_limit > 0)
125
- {
126
- return true;
127
- }
128
- else
129
- return false;
130
- }
131
-
132
- function pmpro_getLevelCost(&$level)
133
- {
134
- $r = '
135
- The price for membership is <strong>$' . number_format($level->initial_payment, 2) . '</strong> ';
136
- if($level->billing_amount != '0.00')
137
- {
138
- $r .= 'and then <strong>$' . $level->billing_amount;
139
- if($level->cycle_number == '1')
140
- {
141
- $r .= ' per ';
142
- }
143
- else
144
- {
145
- $r .= 'every ' . $level->cycle_number . ' ';
146
- }
147
-
148
- $r .= sornot($level->cycle_period,$level->cycle_number);
149
-
150
- if($level->billing_limit)
151
- {
152
- $r .= ' for ' . $level->billing_limit . ' ' . sornot($level->cycle_period,$level->billing_limit) . '.';
153
- }
154
- else
155
- $r .= '.';
156
-
157
- $r .= '</strong>';
158
- }
159
-
160
- if($level->trial_limit)
161
- {
162
- $r .= ' After your initial payment, your first ';
163
- if($level->trial_amount == '0.00')
164
- {
165
- if($level->trial_limit == '1')
166
- {
167
- $r .= 'payment is Free.';
168
- }
169
- else
170
- {
171
- $r .= $level->trial_limit . ' payments are Free.';
172
- }
173
- }
174
- else
175
- {
176
- $r .= $level->trial_limit.' ' .sornot("payment", $level->trial_limit) . ' will cost $' . $level->trial_amount . '.';
177
- }
178
- }
179
-
180
- //taxes?
181
- $tax_state = pmpro_getOption("tax_state");
182
- $tax_rate = pmpro_getOption("tax_rate");
183
-
184
- if($tax_state && $tax_rate)
185
- {
186
- $r .= " Customers in " . $tax_state . " will be charged " . round($tax_rate * 100) . "% tax.";
187
- }
188
-
189
- return $r;
190
- }
191
-
192
- function pmpro_hideAds()
193
- {
194
- global $pmpro_display_ads;
195
- return !$pmpro_display_ads;
196
- }
197
-
198
- function pmpro_displayAds()
199
- {
200
- global $pmpro_display_ads;
201
- return $pmpro_display_ads;
202
- }
203
-
204
- function pmpro_next_payment($user_id = NULL)
205
- {
206
- global $wpdb, $current_user;
207
- if(!$user_id)
208
- $user_id = $current_user->ID;
209
-
210
- if(!$user_id)
211
- return false;
212
-
213
- //when were they last billed
214
- $lastdate = $wpdb->get_var("SELECT UNIX_TIMESTAMP(timestamp) as timestamp FROM $wpdb->pmpro_membership_orders WHERE user_id = '" . $user_id . "' ORDER BY timestamp DESC LIMIT 1");
215
-
216
- if($lastdate)
217
- {
218
- //next payment will be same day, following month
219
- $lastmonth = date("n", $lastdate);
220
- $lastday = date("j", $lastdate);
221
- $lastyear = date("Y", $lastdate);
222
-
223
- $nextmonth = ((int)$lastmonth) + 1;
224
- if($nextmonth == 13)
225
- {
226
- $nextmonth = 1;
227
- $nextyear = ((int)$lastyear) + 1;
228
- }
229
- else
230
- $nextyear = $lastyear;
231
-
232
- $daysinnextmonth = date("t", strtotime($nextyear . "-" . $nextmonth . "-1"));
233
-
234
- if($daysinnextmonth < $lastday)
235
- {
236
- $nextday = $daysinnextmonth;
237
- }
238
- else
239
- $nextday = $lastday;
240
-
241
- return strtotime($nextyear . "-" . $nextmonth . "-" . $nextday);
242
- }
243
- else
244
- {
245
- return false;
246
- }
247
-
248
- }
249
-
250
- if(!function_exists("last4"))
251
- {
252
- function last4($t)
253
- {
254
- return substr($t, strlen($t) - 4, 4);
255
- }
256
- }
257
-
258
- if(!function_exists("hideCardNumber"))
259
- {
260
- function hideCardNumber($c, $dashes = true)
261
- {
262
- if($c)
263
- {
264
- if($dashes)
265
- return "XXXX-XXXX-XXXX-" . substr($c, strlen($c) - 4, 4);
266
- else
267
- return "XXXXXXXXXXXX" . substr($c, strlen($c) - 4, 4);
268
- }
269
- else
270
- {
271
- return "";
272
- }
273
- }
274
- }
275
-
276
- if(!function_exists("cleanPhone"))
277
- {
278
- function cleanPhone($phone)
279
- {
280
- //clean the phone
281
- $phone = str_replace("-", "", $phone);
282
- $phone = str_replace(".", "", $phone);
283
- $phone = str_replace("(", "", $phone);
284
- $phone = str_replace(")", "", $phone);
285
- $phone = str_replace(" ", "", $phone);
286
-
287
- return $phone;
288
- }
289
- }
290
-
291
- if(!function_exists("formatPhone"))
292
- {
293
- function formatPhone($phone)
294
- {
295
- $phone = cleanPhone($phone);
296
-
297
- if(strlen($phone) == 11)
298
- return substr($phone, 0, 1) . " (" . substr($phone, 1, 3) . ") " . substr($phone, 4, 3) . "-" . substr($phone, 7, 4);
299
- elseif(strlen($phone) == 10)
300
- return "(" . substr($phone, 0, 3) . ") " . substr($phone, 3, 3) . "-" . substr($phone, 6, 4);
301
- elseif(strlen($phone) == 7)
302
- return substr($phone, 0, 3) . "-" . substr($phone, 3, 4);
303
- else
304
- return $phone;
305
- }
306
- }
307
-
308
- function pmpro_showRequiresMembershipMessage()
309
- {
310
- //get the correct message
311
- if(is_feed())
312
- {
313
- $content = pmpro_getOption("rsstext");
314
- $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content);
315
- }
316
- elseif($current_user->ID)
317
- {
318
- //not a member
319
- $content = pmpro_getOption("nonmembertext");
320
- $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content);
321
- }
322
- else
323
- {
324
- //not logged in!
325
- $content = pmpro_getOption("notloggedintext");
326
- $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content);
327
- }
328
- }
329
-
330
- /* pmpro_hasMembershipLevel() checks if the passed user is a member of the passed level
331
- *
332
- * $level may either be the ID or name of the desired membership_level. (or an array of such)
333
- * If $user_id is omitted, the value will be retrieved from $current_user.
334
- *
335
- * Return values:
336
- * Success returns boolean true.
337
- * Failure returns a string containing the error message.
338
- */
339
- function pmpro_hasMembershipLevel($levels = NULL, $user_id = NULL)
340
- {
341
- global $current_user, $all_membership_levels, $wpdb;
342
-
343
- if($user_id)
344
- {
345
- //get the membership level from the global array
346
- $membership_level = $all_membership_levels[$user_id];
347
- if(!$membership_level)
348
- {
349
- //no level, check the db and add to array
350
- $membership_level = $wpdb->get_row("SELECT l.id AS ID, l.*
351
- FROM {$wpdb->pmpro_membership_levels} AS l
352
- JOIN {$wpdb->pmpro_memberships_users} AS mu ON (l.id = mu.membership_id)
353
- WHERE mu.user_id = $user_id
354
- LIMIT 1");
355
- if($membership_level)
356
- $all_membership_levels[$user_id] = $membership_level;
357
- else
358
- $all_memberships_levels[$user_id] = -1; //not a member of anything
359
- }
360
- }
361
- else
362
- {
363
- //no user_id passed, check the current user
364
- $user_id = $current_user->ID;
365
- $membership_level = $current_user->membership_level;
366
- }
367
-
368
- //if 0 was passed, return true if they have no level and false if they have any
369
- if(is_array($levels))
370
- {
371
- if($levels[0] === "0")
372
- {
373
- if($membership_level->ID)
374
- return false;
375
- else
376
- return true;
377
- }
378
- }
379
- else
380
- {
381
- if($levels === "0")
382
- {
383
- if($membership_level->ID)
384
- return false;
385
- else
386
- return true;
387
- }
388
- }
389
-
390
- //no levels?
391
- if($membership_level == "-1" || !$membership_level)
392
- return false;
393
-
394
- //if no level var was passed, we're just checking if they have any level
395
- if(!$levels)
396
- {
397
- if($membership_level->ID)
398
- return true;
399
- else
400
- return false;
401
- }
402
-
403
- //okay, so something to check let's set the levels
404
- if(!is_array($levels))
405
- $levels = array($levels);
406
-
407
- //and check each one
408
- foreach($levels as $level)
409
- {
410
- if($level == $membership_level->ID || $level == $membership_level->name)
411
- {
412
- return true;
413
- }
414
- }
415
-
416
- return false;
417
- }
418
-
419
- /* pmpro_changeMembershipLevel() creatues or updates the membership level of the given user to the given level.
420
- *
421
- * $level may either be the ID or name of the desired membership_level.
422
- * If $user_id is omitted, the value will be retrieved from $current_user.
423
- *
424
- * Return values:
425
- * Success returns boolean true.
426
- * Failure returns boolean false.
427
- */
428
- function pmpro_changeMembershipLevel($level, $user_id = NULL)
429
- {
430
- global $wpdb;
431
- global $current_user, $pmpro_error;
432
-
433
- if(!$user_id)
434
- $user_id = $current_user->ID;
435
-
436
- if(!$user_id)
437
- {
438
- $pmpro_error = "User ID not found.";
439
- return false;
440
- }
441
-
442
- //was a name passed? (Todo: make sure level names have at least one non-numeric character.
443
- if($level !== "" && $level !== false && $level !== NULL && !is_numeric($level))
444
- {
445
- $level = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_levels WHERE name = '" . $wpdb->escape($level) . "' LIMIT 1");
446
- if(!$level)
447
- {
448
- $pmpro_error = "Membership level not found.";
449
- return false;
450
- }
451
- }
452
-
453
- //are they even changing?
454
- $old_level = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_memberships_users WHERE user_id = '" . $user_id . "'");
455
- if($old_level->membership_id == $level)
456
- return false; //not changing
457
-
458
- //are they paying? may need to cancel their old membership
459
- if(!pmpro_isLevelFree($old_level))
460
- $paying = true;
461
-
462
- if($paying)
463
- {
464
- //get last order
465
- $order = new MemberOrder();
466
- $order->getLastMemberOrder($user_id);
467
-
468
- if($order->subscription_transaction_id)
469
- {
470
- if($order->cancel())
471
- {
472
- //we're good
473
- }
474
- else
475
- {
476
- //uh oh
477
- $pmpro_error = "There was an error canceling your membership: " . $order->error;
478
- return false;
479
- }
480
- }
481
- }
482
-
483
- //adding, changing, or deleting
484
- if($level)
485
- {
486
- //adding, changing
487
- $sql = "REPLACE INTO $wpdb->pmpro_memberships_users (`membership_id`,`user_id`) VALUES ('" . $level . "','" . $user_id . "')";
488
- }
489
- else
490
- {
491
- //false or null or 0 was passed, so we're deleting removing
492
- $sql = "DELETE FROM $wpdb->pmpro_memberships_users WHERE user_id = '" . $wpdb->escape($user_id) . "' LIMIT 1";
493
- }
494
-
495
- //run the query, return
496
- if(!$wpdb->query($sql))
497
- {
498
- if(mysql_errno())
499
- $pmpro_error = "Error: " . mysql_error();
500
- return false;
501
- }
502
- else
503
- {
504
- pmpro_set_current_user();
505
- do_action("pmpro_after_change_membership_level", $level, $user_id);
506
- return true;
507
- }
508
- }
509
-
510
- /* pmpro_toggleMembershipCategory() creates or deletes a linking entry between the membership level and post category tables.
511
- *
512
- * $level may either be the ID or name of the desired membership_level.
513
- * $category must be a valid post category ID.
514
- *
515
- * Return values:
516
- * Success returns boolean true.
517
- * Failure returns a string containing the error message.
518
- */
519
- function pmpro_toggleMembershipCategory( $level, $category, $value )
520
- {
521
- global $wpdb;
522
- $category = intval($category);
523
-
524
- if ( ($level = intval($level)) <= 0 )
525
- {
526
- $safe = addslashes($level);
527
- if ( ($level = intval($wpdb->get_var("SELECT id FROM {$wpdb->pmpro_membership_levels} WHERE name = '$safe' LIMIT 1"))) <= 0 )
528
- {
529
- return "Membership level not found.";
530
- }
531
- }
532
-
533
- if ( $value )
534
- {
535
- $sql = "REPLACE INTO {$wpdb->pmpro_memberships_categories} (`membership_id`,`category_id`) VALUES ('$level','$category')";
536
- $wpdb->query($sql);
537
- if(mysql_errno()) return mysql_error();
538
- }
539
- else
540
- {
541
- $sql = "DELETE FROM {$wpdb->pmpro_memberships_categories} WHERE `membership_id` = '$level' AND `category_id` = '$category' LIMIT 1";
542
- $wpdb->query($sql);
543
- if(mysql_errno()) return mysql_error();
544
- }
545
-
546
- return true;
547
- }
548
-
549
- /* pmpro_updateMembershipCategories() ensures that all those and only those categories given
550
- * are associated with the given membership level.
551
- *
552
- * $level is a valid membership level ID or name
553
- * $categories is an array of post category IDs
554
- *
555
- * Return values:
556
- * Success returns boolean true.
557
- * Failure returns a string containing the error message.
558
- */
559
- function pmpro_updateMembershipCategories( $level, $categories ) {
560
- global $wpdb;
561
- $category = intval($category);
562
-
563
- if ( ($level = intval($level)) <= 0 )
564
- {
565
- $safe = addslashes($level);
566
- if ( ($level = intval($wpdb->get_var("SELECT id FROM {$wpdb->pmpro_membership_levels} WHERE name = '$safe' LIMIT 1"))) <= 0 )
567
- {
568
- return "Membership level not found.";
569
- }
570
- }
571
-
572
- // remove all existing links...
573
- $sql = "DELETE FROM {$wpdb->pmpro_memberships_categories} WHERE `membership_id` = '$level'";
574
- $wpdb->query($sql);
575
- if(mysql_errno()) return mysql_error();
576
-
577
- // add the given links [back?] in...
578
- foreach ( $categories as $cat )
579
- {
580
- if ( is_string( $r = pmpro_toggleMembershipCategory( $level, $cat, true ) ) )
581
- {
582
- return $r;
583
- }
584
- }
585
-
586
- return true;
587
- }
588
-
589
- function pmpro_isAdmin($user_id = NULL)
590
- {
591
- global $current_user, $wpdb;
592
- if(!$user_id)
593
- $user_id = $current_user->ID;
594
-
595
- if(!$user_id)
596
- return false;
597
-
598
- $admincap = user_can($user_id, "manage_options");
599
- if($admincap)
600
- return true;
601
- else
602
- return false;
603
- }
604
-
605
- function pmpro_replaceUserMeta($user_id, $meta_keys, $meta_values, $prev_values = NULL)
606
- {
607
- //expects all arrays for last 3 params or all strings
608
- if(!is_array($meta_keys))
609
- {
610
- $meta_keys = array($meta_keys);
611
- $meta_values = array($meta_values);
612
- $prev_values = array($prev_values);
613
- }
614
-
615
- for($i = 0; $i < count($meta_values); $i++)
616
- {
617
- if($prev_values[$i])
618
- {
619
- update_user_meta($user_id, $meta_keys[$i], $meta_values[$i], $prev_values[$i]);
620
- }
621
- else
622
- {
623
- $old_value = get_user_meta($user_id, $meta_keys[$i], true);
624
- if($old_value)
625
- {
626
- update_user_meta($user_id, $meta_keys[$i], $meta_values[$i], $old_value);
627
- }
628
- else
629
- {
630
- update_user_meta($user_id, $meta_keys[$i], $meta_values[$i]);
631
- }
632
- }
633
- }
634
-
635
- return $i;
636
- }
637
-
638
- function pmpro_getMetavalues($query)
639
- {
640
- global $wpdb;
641
-
642
- $results = $wpdb->get_results($query);
643
- foreach($results as $result)
644
- {
645
- $r->{$result->key} = $result->value;
646
- }
647
-
648
- return $r;
649
- }
650
-
651
- //function to return the pagination string
652
- function pmpro_getPaginationString($page = 1, $totalitems, $limit = 15, $adjacents = 1, $targetpage = "/", $pagestring = "&pn=")
653
- {
654
- //defaults
655
- if(!$adjacents) $adjacents = 1;
656
- if(!$limit) $limit = 15;
657
- if(!$page) $page = 1;
658
- if(!$targetpage) $targetpage = "/";
659
-
660
- //other vars
661
- $prev = $page - 1; //previous page is page - 1
662
- $next = $page + 1; //next page is page + 1
663
- $lastpage = ceil($totalitems / $limit); //lastpage is = total items / items per page, rounded up.
664
- $lpm1 = $lastpage - 1; //last page minus 1
665
-
666
- /*
667
- Now we apply our rules and draw the pagination object.
668
- We're actually saving the code to a variable in case we want to draw it more than once.
669
- */
670
- $pagination = "";
671
- if($lastpage > 1)
672
- {
673
- $pagination .= "<div class=\"pagination\"";
674
- if($margin || $padding)
675
- {
676
- $pagination .= " style=\"";
677
- if($margin)
678
- $pagination .= "margin: $margin;";
679
- if($padding)
680
- $pagination .= "padding: $padding;";
681
- $pagination .= "\"";
682
- }
683
- $pagination .= ">";
684
-
685
- //previous button
686
- if ($page > 1)
687
- $pagination .= "<a href=\"$targetpage$pagestring$prev\">&laquo; prev</a>";
688
- else
689
- $pagination .= "<span class=\"disabled\">&laquo; prev</span>";
690
-
691
- //pages
692
- if ($lastpage < 7 + ($adjacents * 2)) //not enough pages to bother breaking it up
693
- {
694
- for ($counter = 1; $counter <= $lastpage; $counter++)
695
- {
696
- if ($counter == $page)
697
- $pagination .= "<span class=\"current\">$counter</span>";
698
- else
699
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
700
- }
701
- }
702
- elseif($lastpage >= 7 + ($adjacents * 2)) //enough pages to hide some
703
- {
704
- //close to beginning; only hide later pages
705
- if($page < 1 + ($adjacents * 3))
706
- {
707
- for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++)
708
- {
709
- if ($counter == $page)
710
- $pagination .= "<span class=\"current\">$counter</span>";
711
- else
712
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
713
- }
714
- $pagination .= "...";
715
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $lpm1 . "\">$lpm1</a>";
716
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $lastpage . "\">$lastpage</a>";
717
- }
718
- //in middle; hide some front and some back
719
- elseif($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2))
720
- {
721
- $pagination .= "<a href=\"" . $targetpage . $pagestring . "1\">1</a>";
722
- $pagination .= "<a href=\"" . $targetpage . $pagestring . "2\">2</a>";
723
- $pagination .= "...";
724
- for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++)
725
- {
726
- if ($counter == $page)
727
- $pagination .= "<span class=\"current\">$counter</span>";
728
- else
729
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
730
- }
731
- $pagination .= "...";
732
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $lpm1 . "\">$lpm1</a>";
733
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $lastpage . "\">$lastpage</a>";
734
- }
735
- //close to end; only hide early pages
736
- else
737
- {
738
- $pagination .= "<a href=\"" . $targetpage . $pagestring . "1\">1</a>";
739
- $pagination .= "<a href=\"" . $targetpage . $pagestring . "2\">2</a>";
740
- $pagination .= "...";
741
- for ($counter = $lastpage - (1 + ($adjacents * 3)); $counter <= $lastpage; $counter++)
742
- {
743
- if ($counter == $page)
744
- $pagination .= "<span class=\"current\">$counter</span>";
745
- else
746
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
747
- }
748
- }
749
- }
750
-
751
- //next button
752
- if ($page < $counter - 1)
753
- $pagination .= "<a href=\"" . $targetpage . $pagestring . $next . "\">next &raquo;</a>";
754
- else
755
- $pagination .= "<span class=\"disabled\">next &raquo;</span>";
756
- $pagination .= "</div>\n";
757
- }
758
-
759
- return $pagination;
760
-
761
- }
762
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ //setup wpdb for the tables we need
32
+ function pmpro_setDBTables()
33
+ {
34
+ global $table_prefix, $wpdb;
35
+ $wpdb->hide_errors();
36
+ $wpdb->pmpro_membership_levels = $table_prefix . 'pmpro_membership_levels';
37
+ $wpdb->pmpro_memberships_users = $table_prefix . 'pmpro_memberships_users';
38
+ $wpdb->pmpro_memberships_categories = $table_prefix . 'pmpro_memberships_categories';
39
+ $wpdb->pmpro_memberships_pages = $table_prefix . 'pmpro_memberships_pages';
40
+ $wpdb->pmpro_membership_orders = $table_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(isset($_REQUEST[$s]) && !$force)
90
+ {
91
+ if(!is_array($_REQUEST[$s]))
92
+ return trim($_REQUEST[$s]);
93
+ else
94
+ return $_REQUEST[$s];
95
+ }
96
+ elseif(get_option("pmpro_" . $s))
97
+ return get_option("pmpro_" . $s);
98
+ else
99
+ return "";
100
+ }
101
+
102
+ function pmpro_setOption($s, $v = NULL)
103
+ {
104
+ //no value is given, set v to the request var
105
+ if($v === NULL && isset($_REQUEST[$s]))
106
+ $v = $_REQUEST[$s];
107
+
108
+ if(is_array($v))
109
+ $v = implode(",", $v);
110
+ else
111
+ $v = trim($v);
112
+
113
+ return update_option("pmpro_" . $s, $v);
114
+ }
115
+
116
+ function pmpro_get_slug($post_id)
117
+ {
118
+ global $pmpro_slugs, $wpdb;
119
+ if(!$pmpro_slugs[$post_id])
120
+ $pmpro_slugs[$post_id] = $wpdb->get_var("SELECT post_name FROM $wpdb->posts WHERE ID = '" . $post_id . "' LIMIT 1");
121
+
122
+ return $pmpro_slugs[$post_id];
123
+ }
124
+
125
+ function pmpro_url($page = NULL, $querystring = "", $scheme = NULL)
126
+ {
127
+ global $besecure;
128
+ $besecure = apply_filters("besecure", $besecure);
129
+
130
+ if(!$scheme && $besecure)
131
+ $scheme = "https";
132
+ elseif(!$scheme)
133
+ $scheme = "http";
134
+
135
+ if(!$page)
136
+ $page = "levels";
137
+
138
+ global $pmpro_pages;
139
+
140
+ //start with the permalink
141
+ $url = get_permalink($pmpro_pages[$page]);
142
+
143
+ //WPML/etc support
144
+ if(function_exists("icl_object_id") && defined("ICL_LANGUAGE_CODE"))
145
+ {
146
+ $trans_id = icl_object_id($pmpro_pages[$page], "page", false, ICL_LANGUAGE_CODE);
147
+ if(!empty($trans_id))
148
+ {
149
+ $url = get_permalink($trans_id);
150
+ }
151
+ }
152
+
153
+ //figure out querystring
154
+ if(strpos($url, "?"))
155
+ $querystring = str_replace("?", "&", $querystring);
156
+ $url .= $querystring;
157
+
158
+ //figure out scheme
159
+ if(is_ssl())
160
+ $url = str_replace("http:", "https:", $url);
161
+
162
+ return $url;
163
+ }
164
+
165
+ function pmpro_isLevelFree(&$level)
166
+ {
167
+ if(!empty($level) && $level->initial_payment <= 0 && $level->billing_amount <= 0 && $level->trial_amount <= 0)
168
+ return true;
169
+ else
170
+ return false;
171
+ }
172
+
173
+ function pmpro_isLevelRecurring(&$level)
174
+ {
175
+ if(!empty($level) && ($level->billing_amount > 0 || $level->trial_amount > 0))
176
+ return true;
177
+ else
178
+ return false;
179
+ }
180
+
181
+ function pmpro_isLevelTrial(&$level)
182
+ {
183
+ if($level->trial_limit > 0)
184
+ {
185
+ return true;
186
+ }
187
+ else
188
+ return false;
189
+ }
190
+
191
+ function pmpro_isLevelExpiring(&$level)
192
+ {
193
+ if($level->expiration_number > 0)
194
+ return true;
195
+ else
196
+ return false;
197
+ }
198
+
199
+ function pmpro_getLevelCost(&$level, $tags = true, $short = false)
200
+ {
201
+ //initial payment
202
+ if(!$short)
203
+ $r = sprintf(__('The price for membership is <strong>%s</strong> now', 'pmpro'), pmpro_formatPrice($level->initial_payment));
204
+ else
205
+ $r = sprintf(__('<strong>%s</strong> now', 'pmpro'), pmpro_formatPrice($level->initial_payment));
206
+
207
+ //recurring part
208
+ if($level->billing_amount != '0.00')
209
+ {
210
+ if($level->billing_limit > 1)
211
+ {
212
+ if($level->cycle_number == '1')
213
+ {
214
+ $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));
215
+ }
216
+ else
217
+ {
218
+ $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));
219
+ }
220
+ }
221
+ elseif($level->billing_limit == 1)
222
+ {
223
+ $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));
224
+ }
225
+ else
226
+ {
227
+ if( $level->billing_amount === $level->initial_payment ) {
228
+ if($level->cycle_number == '1')
229
+ {
230
+ $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) );
231
+ }
232
+ else
233
+ {
234
+ $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) );
235
+ }
236
+ } else {
237
+ if($level->cycle_number == '1')
238
+ {
239
+ $r .= sprintf(__(' and then <strong>%s per %s</strong>.', 'pmpro'), pmpro_formatPrice($level->billing_amount), pmpro_translate_billing_period($level->cycle_period));
240
+ }
241
+ else
242
+ {
243
+ $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));
244
+ }
245
+ }
246
+ }
247
+ }
248
+ else
249
+ $r .= '.';
250
+
251
+ //add a space
252
+ $r .= ' ';
253
+
254
+ //trial part
255
+ if($level->trial_limit)
256
+ {
257
+ if($level->trial_amount == '0.00')
258
+ {
259
+ if($level->trial_limit == '1')
260
+ {
261
+ $r .= ' ' . __('After your initial payment, your first payment is Free.', 'pmpro');
262
+ }
263
+ else
264
+ {
265
+ $r .= ' ' . sprintf(__('After your initial payment, your first %d payments are Free.', 'pmpro'), $level->trial_limit);
266
+ }
267
+ }
268
+ else
269
+ {
270
+ if($level->trial_limit == '1')
271
+ {
272
+ $r .= ' ' . sprintf(__('After your initial payment, your first payment will cost %s.', 'pmpro'), pmpro_formatPrice($level->trial_amount));
273
+ }
274
+ else
275
+ {
276
+ $r .= ' ' . sprintf(__('After your initial payment, your first %d payments will cost %s.', 'pmpro'), $level->trial_limit, pmpro_formatPrice($level->trial_amount));
277
+ }
278
+ }
279
+ }
280
+
281
+ //taxes part
282
+ $tax_state = pmpro_getOption("tax_state");
283
+ $tax_rate = pmpro_getOption("tax_rate");
284
+
285
+ if($tax_state && $tax_rate && !pmpro_isLevelFree($level))
286
+ {
287
+ $r .= sprintf(__('Customers in %s will be charged %s%% tax.', 'pmpro'), $tax_state, round($tax_rate * 100, 2));
288
+ }
289
+
290
+ if(!$tags)
291
+ $r = strip_tags($r);
292
+
293
+ $r = apply_filters("pmpro_level_cost_text", $r, $level);
294
+ return $r;
295
+ }
296
+
297
+ function pmpro_getLevelExpiration(&$level)
298
+ {
299
+ if($level->expiration_number)
300
+ {
301
+ $expiration_text = sprintf(__("Membership expires after %d %s.", "pmpro"), $level->expiration_number, pmpro_translate_billing_period($level->expiration_period, $level->expiration_number));
302
+ }
303
+ else
304
+ $expiration_text = "";
305
+
306
+ $expiration_text = apply_filters("pmpro_level_expiration_text", $expiration_text, $level);
307
+ return $expiration_text;
308
+ }
309
+
310
+ function pmpro_hideAds()
311
+ {
312
+ global $pmpro_display_ads;
313
+ return !$pmpro_display_ads;
314
+ }
315
+
316
+ function pmpro_displayAds()
317
+ {
318
+ global $pmpro_display_ads;
319
+ return $pmpro_display_ads;
320
+ }
321
+
322
+ function pmpro_next_payment($user_id = NULL, $order_status = "success")
323
+ {
324
+ global $wpdb, $current_user;
325
+ if(!$user_id)
326
+ $user_id = $current_user->ID;
327
+
328
+ if(!$user_id)
329
+ return false;
330
+
331
+ //get last order
332
+ $order = new MemberOrder();
333
+ $order->getLastMemberOrder($user_id, $order_status);
334
+
335
+ //get current membership level
336
+ $level = pmpro_getMembershipLevelForUser($user_id);
337
+
338
+ if(!empty($order) && !empty($order->id) && !empty($level) && !empty($level->id) && !empty($level->cycle_number))
339
+ {
340
+ //last payment date
341
+ $lastdate = date("Y-m-d", $order->timestamp);
342
+
343
+ //next payment date
344
+ $nextdate = $wpdb->get_var("SELECT UNIX_TIMESTAMP('" . $lastdate . "' + INTERVAL " . $level->cycle_number . " " . $level->cycle_period . ")");
345
+
346
+ return $nextdate;
347
+ }
348
+ else
349
+ {
350
+ //no order or level found, or level was not recurring
351
+ return false;
352
+ }
353
+ }
354
+
355
+ if(!function_exists("last4"))
356
+ {
357
+ function last4($t)
358
+ {
359
+ return substr($t, strlen($t) - 4, 4);
360
+ }
361
+ }
362
+
363
+ if(!function_exists("hideCardNumber"))
364
+ {
365
+ function hideCardNumber($c, $dashes = true)
366
+ {
367
+ if($c)
368
+ {
369
+ if($dashes)
370
+ return "XXXX-XXXX-XXXX-" . substr($c, strlen($c) - 4, 4);
371
+ else
372
+ return "XXXXXXXXXXXX" . substr($c, strlen($c) - 4, 4);
373
+ }
374
+ else
375
+ {
376
+ return "";
377
+ }
378
+ }
379
+ }
380
+
381
+ if(!function_exists("cleanPhone"))
382
+ {
383
+ function cleanPhone($phone)
384
+ {
385
+ //if a + is passed, just pass it along
386
+ if(strpos($phone, "+") !== false)
387
+ return $phone;
388
+
389
+ //clean the phone
390
+ $phone = str_replace("-", "", $phone);
391
+ $phone = str_replace(".", "", $phone);
392
+ $phone = str_replace("(", "", $phone);
393
+ $phone = str_replace(")", "", $phone);
394
+ $phone = str_replace(" ", "", $phone);
395
+
396
+ return $phone;
397
+ }
398
+ }
399
+
400
+ if(!function_exists("formatPhone"))
401
+ {
402
+ function formatPhone($phone)
403
+ {
404
+ $phone = cleanPhone($phone);
405
+
406
+ if(strlen($phone) == 11)
407
+ return substr($phone, 0, 1) . " (" . substr($phone, 1, 3) . ") " . substr($phone, 4, 3) . "-" . substr($phone, 7, 4);
408
+ elseif(strlen($phone) == 10)
409
+ return "(" . substr($phone, 0, 3) . ") " . substr($phone, 3, 3) . "-" . substr($phone, 6, 4);
410
+ elseif(strlen($phone) == 7)
411
+ return substr($phone, 0, 3) . "-" . substr($phone, 3, 4);
412
+ else
413
+ return $phone;
414
+ }
415
+ }
416
+
417
+ function pmpro_showRequiresMembershipMessage()
418
+ {
419
+ //get the correct message
420
+ if(is_feed())
421
+ {
422
+ $content = pmpro_getOption("rsstext");
423
+ $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content);
424
+ }
425
+ elseif($current_user->ID)
426
+ {
427
+ //not a member
428
+ $content = pmpro_getOption("nonmembertext");
429
+ $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content);
430
+ }
431
+ else
432
+ {
433
+ //not logged in!
434
+ $content = pmpro_getOption("notloggedintext");
435
+ $content = str_replace("!!levels!!", implode(", ", $post_membership_levels_names), $content);
436
+ }
437
+ }
438
+
439
+ /* pmpro_hasMembershipLevel() checks if the passed user is a member of the passed level
440
+ *
441
+ * $level may either be the ID or name of the desired membership_level. (or an array of such)
442
+ * If $user_id is omitted, the value will be retrieved from $current_user.
443
+ *
444
+ * Return values:
445
+ * Success returns boolean true.
446
+ * Failure returns a string containing the error message.
447
+ */
448
+ function pmpro_hasMembershipLevel($levels = NULL, $user_id = NULL)
449
+ {
450
+ global $current_user, $all_membership_levels, $wpdb;
451
+
452
+ $return = false;
453
+
454
+ if(empty($user_id)) //no user_id passed, check the current user
455
+ {
456
+ $user_id = $current_user->ID;
457
+ $membership_levels = $current_user->membership_levels;
458
+ }
459
+ else //get membership levels for given user
460
+ {
461
+ $membership_levels = pmpro_getMembershipLevelsForUser($user_id);
462
+ }
463
+
464
+ if($levels === "0" || $levels === 0) //if 0 was passed, return true if they have no level and false if they have any
465
+ {
466
+ $return = empty($membership_levels);
467
+ }
468
+ elseif(empty($levels)) //if no level var was passed, we're just checking if they have any level
469
+ {
470
+ $return = !empty($membership_levels);
471
+ }
472
+ else
473
+ {
474
+ if(!is_array($levels)) //make an array out of a single element so we can use the same code
475
+ {
476
+ $levels = array($levels);
477
+ }
478
+
479
+ if(empty($membership_levels))
480
+ {
481
+ //user has no levels just check if 0 was sent in one of the levels
482
+ if(in_array(0, $levels) || in_array("0", $levels))
483
+ $return = true;
484
+ }
485
+ else
486
+ {
487
+ foreach($levels as $level)
488
+ {
489
+ $level_obj = pmpro_getLevel(is_numeric($level) ? abs(intval($level)) : $level); //make sure our level is in a proper format
490
+ if(empty($level_obj)){continue;} //invalid level
491
+ $found_level = false;
492
+ foreach($membership_levels as $membership_level)
493
+ {
494
+ if($membership_level->id == $level_obj->id) //found a match
495
+ {
496
+ $found_level = true;
497
+ }
498
+ }
499
+
500
+ if(is_numeric($level) and intval($level) < 0 and !$found_level) //checking for the absence of this level
501
+ {
502
+ $return = true;
503
+ }
504
+ else if($found_level) //checking for the presence of this level
505
+ {
506
+ $return = true;
507
+ }
508
+ }
509
+ }
510
+ }
511
+
512
+ $return = apply_filters("pmpro_has_membership_level", $return, $user_id, $levels);
513
+ return $return;
514
+ }
515
+
516
+ /* pmpro_changeMembershipLevel() creates or updates the membership level of the given user to the given level.
517
+ *
518
+ * $level may either be the ID or name of the desired membership_level.
519
+ * If $user_id is omitted, the value will be retrieved from $current_user.
520
+ *
521
+ * Return values:
522
+ * Success returns boolean true.
523
+ * Failure returns boolean false.
524
+ */
525
+ function pmpro_changeMembershipLevel($level, $user_id = NULL)
526
+ {
527
+ global $wpdb;
528
+ global $current_user, $pmpro_error;
529
+
530
+ if(empty($user_id))
531
+ {
532
+ $user_id = $current_user->ID;
533
+ }
534
+
535
+ if(empty($user_id))
536
+ {
537
+ $pmpro_error = __("User ID not found.", "pmpro");
538
+ return false;
539
+ }
540
+
541
+ if(empty($level)) //cancelling membership
542
+ {
543
+ $level = 0;
544
+ }
545
+ else if(is_array($level))
546
+ {
547
+ //custom level
548
+ }
549
+ else
550
+ {
551
+ $level_obj = pmpro_getLevel($level);
552
+ if(empty($level_obj))
553
+ {
554
+ $pmpro_error = __("Invalid level.", "pmpro");
555
+ return false;
556
+ }
557
+ $level = $level_obj->id;
558
+ }
559
+
560
+ //if it's a custom level, they're changing
561
+ if(!is_array($level))
562
+ {
563
+ //are they even changing?
564
+ if(pmpro_hasMembershipLevel($level, $user_id)) {
565
+ $pmpro_error = __("not changing?", "pmpro");
566
+ return false; //not changing
567
+ }
568
+ }
569
+
570
+ $old_levels = pmpro_getMembershipLevelsForUser($user_id);
571
+
572
+ $pmpro_cancel_previous_subscriptions = apply_filters("pmpro_cancel_previous_subscriptions", true);
573
+ if($pmpro_cancel_previous_subscriptions)
574
+ {
575
+ //deactivate old memberships (updates pmpro_memberships_users table)
576
+ if(!empty($old_levels))
577
+ {
578
+ foreach($old_levels as $old_level) {
579
+ $sql = "UPDATE $wpdb->pmpro_memberships_users SET `status`='inactive', `enddate`='" . current_time('mysql') . "' WHERE `id`=".$old_level->subscription_id;
580
+ if(!$wpdb->query($sql))
581
+ {
582
+ $pmpro_error = __("Error interacting with database", "pmpro") . ": ".(mysql_errno()?mysql_error():'unavailable');
583
+ return false;
584
+ }
585
+ }
586
+ }
587
+
588
+ //cancel any other subscriptions they have (updates pmpro_membership_orders table)
589
+ $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");
590
+
591
+ foreach($other_order_ids as $order_id)
592
+ {
593
+ $c_order = new MemberOrder($order_id);
594
+ $c_order->cancel();
595
+
596
+ if(!empty($c_order->error))
597
+ $pmpro_error = $c_order->error;
598
+ }
599
+ }
600
+
601
+ //insert current membership
602
+ if(!empty($level)) //are we getting a new one or just cancelling the old ones
603
+ {
604
+ if(is_array($level))
605
+ {
606
+ //make sure the dates are in good formats
607
+ if($level['startdate'] != current_time('mysql') && $level['startdate'] != "NULL" && substr($level['startdate'], 0, 1) != "'")
608
+ $level['startdate'] = "'" . $level['startdate'] . "'";
609
+
610
+ if($level['enddate'] != current_time('mysql') && $level['enddate'] != "NULL" && substr($level['enddate'], 0, 1) != "'")
611
+ $level['enddate'] = "'" . $level['enddate'] . "'";
612
+
613
+ //Better support mySQL Strict Mode by passing a proper enum value for cycle_period
614
+ if ($level['cycle_period'] == '') $level['cycle_period'] = 0;
615
+
616
+ $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)
617
+ VALUES('" . $level['user_id'] . "',
618
+ '" . $level['membership_id'] . "',
619
+ '" . intval($level['code_id']) . "',
620
+ '" . $level['initial_payment'] . "',
621
+ '" . $level['billing_amount'] . "',
622
+ '" . $level['cycle_number'] . "',
623
+ '" . $level['cycle_period'] . "',
624
+ '" . $level['billing_limit'] . "',
625
+ '" . $level['trial_amount'] . "',
626
+ '" . $level['trial_limit'] . "',
627
+ " . $level['startdate'] . ",
628
+ " . $level['enddate'] . ")";
629
+
630
+ if(!$wpdb->query($sql))
631
+ {
632
+ $pmpro_error = __("Error interacting with database", "pmpro") . ": ".(mysql_errno()?mysql_error():'unavailable');
633
+ return false;
634
+ }
635
+ }
636
+ else
637
+ {
638
+ $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)
639
+ VALUES (
640
+ '" . $user_id . "',
641
+ '" . $level . "',
642
+ '0',
643
+ '0',
644
+ '0',
645
+ '0',
646
+ '0',
647
+ '0',
648
+ '0',
649
+ '0',
650
+ '" . current_time('mysql') . "',
651
+ '0000-00-00 00:00:00'
652
+ )";
653
+
654
+ if(!$wpdb->query($sql))
655
+ {
656
+ $pmpro_error = __("Error interacting with database", "pmpro") . ": ".(mysql_errno()?mysql_error():'unavailable');
657
+ return false;
658
+ }
659
+ }
660
+ }
661
+
662
+ //get level id
663
+ if(is_array($level))
664
+ $level_id = $level['membership_id']; //custom level
665
+ else
666
+ $level_id = $level; //just id
667
+
668
+ //remove cached level
669
+ global $all_membership_levels;
670
+ unset($all_membership_levels[$user_id]);
671
+
672
+ //update user data and call action
673
+ pmpro_set_current_user();
674
+ do_action("pmpro_after_change_membership_level", $level_id, $user_id); //$level is the $level_id here
675
+ return true;
676
+ }
677
+
678
+ /* pmpro_toggleMembershipCategory() creates or deletes a linking entry between the membership level and post category tables.
679
+ *
680
+ * $level may either be the ID or name of the desired membership_level.
681
+ * $category must be a valid post category ID.
682
+ *
683
+ * Return values:
684
+ * Success returns boolean true.
685
+ * Failure returns a string containing the error message.
686
+ */
687
+ function pmpro_toggleMembershipCategory( $level, $category, $value )
688
+ {
689
+ global $wpdb;
690
+ $category = intval($category);
691
+
692
+ if ( ($level = intval($level)) <= 0 )
693
+ {
694
+ $safe = addslashes($level);
695
+ if ( ($level = intval($wpdb->get_var("SELECT id FROM {$wpdb->pmpro_membership_levels} WHERE name = '$safe' LIMIT 1"))) <= 0 )
696
+ {
697
+ return __("Membership level not found.", "pmpro");
698
+ }
699
+ }
700
+
701
+ if ( $value )
702
+ {
703
+ $sql = "REPLACE INTO {$wpdb->pmpro_memberships_categories} (`membership_id`,`category_id`) VALUES ('$level','$category')";
704
+ $wpdb->query($sql);
705
+ if(mysql_errno()) return mysql_error();
706
+ }
707
+ else
708
+ {
709
+ $sql = "DELETE FROM {$wpdb->pmpro_memberships_categories} WHERE `membership_id` = '$level' AND `category_id` = '$category' LIMIT 1";
710
+ $wpdb->query($sql);
711
+ if(mysql_errno()) return mysql_error();
712
+ }
713
+
714
+ return true;
715
+ }
716
+
717
+ /* pmpro_updateMembershipCategories() ensures that all those and only those categories given
718
+ * are associated with the given membership level.
719
+ *
720
+ * $level is a valid membership level ID or name
721
+ * $categories is an array of post category IDs
722
+ *
723
+ * Return values:
724
+ * Success returns boolean true.
725
+ * Failure returns a string containing the error message.
726
+ */
727
+ function pmpro_updateMembershipCategories($level, $categories)
728
+ {
729
+ global $wpdb;
730
+
731
+ if(!is_numeric($level))
732
+ {
733
+ $level = $wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_levels WHERE name = '" . esc_sql($level) . "' LIMIT 1");
734
+ if(empty($level))
735
+ {
736
+ return __("Membership level not found.", "pmpro");
737
+ }
738
+ }
739
+
740
+ // remove all existing links...
741
+ $sqlQuery = "DELETE FROM $wpdb->pmpro_memberships_categories WHERE `membership_id` = '" . esc_sql($level) . "'";
742
+ $wpdb->query($sqlQuery);
743
+ if(mysql_errno()) return mysql_error();
744
+
745
+ // add the given links [back?] in...
746
+ foreach($categories as $cat)
747
+ {
748
+ if(is_string($r = pmpro_toggleMembershipCategory( $level, $cat, true)))
749
+ {
750
+ //uh oh, error
751
+ return $r;
752
+ }
753
+ }
754
+
755
+ //all good
756
+ return true;
757
+ }
758
+
759
+ /* pmpro_getMembershipCategories() returns the categories for a given level
760
+ *
761
+ * $level_id is a valid membership level ID
762
+ *
763
+ * Return values:
764
+ * Success returns boolean true.
765
+ * Failure returns boolean false.
766
+ */
767
+ function pmpro_getMembershipCategories($level_id)
768
+ {
769
+ global $wpdb;
770
+ $categories = $wpdb->get_col("SELECT c.category_id
771
+ FROM {$wpdb->pmpro_memberships_categories} AS c
772
+ WHERE c.membership_id = '" . $level_id . "'");
773
+
774
+ return $categories;
775
+ }
776
+
777
+
778
+ function pmpro_isAdmin($user_id = NULL)
779
+ {
780
+ global $current_user, $wpdb;
781
+ if(!$user_id)
782
+ $user_id = $current_user->ID;
783
+
784
+ if(!$user_id)
785
+ return false;
786
+
787
+ $admincap = user_can($user_id, "manage_options");
788
+ if($admincap)
789
+ return true;
790
+ else
791
+ return false;
792
+ }
793
+
794
+ function pmpro_replaceUserMeta($user_id, $meta_keys, $meta_values, $prev_values = NULL)
795
+ {
796
+ //expects all arrays for last 3 params or all strings
797
+ if(!is_array($meta_keys))
798
+ {
799
+ $meta_keys = array($meta_keys);
800
+ $meta_values = array($meta_values);
801
+ $prev_values = array($prev_values);
802
+ }
803
+
804
+ for($i = 0; $i < count($meta_values); $i++)
805
+ {
806
+ if($prev_values[$i])
807
+ {
808
+ update_user_meta($user_id, $meta_keys[$i], $meta_values[$i], $prev_values[$i]);
809
+ }
810
+ else
811
+ {
812
+ $old_value = get_user_meta($user_id, $meta_keys[$i], true);
813
+ if($old_value)
814
+ {
815
+ update_user_meta($user_id, $meta_keys[$i], $meta_values[$i], $old_value);
816
+ }
817
+ else
818
+ {
819
+ update_user_meta($user_id, $meta_keys[$i], $meta_values[$i]);
820
+ }
821
+ }
822
+ }
823
+
824
+ return $i;
825
+ }
826
+
827
+ function pmpro_getMetavalues($query)
828
+ {
829
+ global $wpdb;
830
+
831
+ $results = $wpdb->get_results($query);
832
+ $r = new stdClass();
833
+ foreach($results as $result)
834
+ {
835
+ $r->{$result->key} = $result->value;
836
+ }
837
+
838
+ return $r;
839
+ }
840
+
841
+ //function to return the pagination string
842
+ function pmpro_getPaginationString($page = 1, $totalitems, $limit = 15, $adjacents = 1, $targetpage = "/", $pagestring = "&pn=")
843
+ {
844
+ //defaults
845
+ if(!$adjacents) $adjacents = 1;
846
+ if(!$limit) $limit = 15;
847
+ if(!$page) $page = 1;
848
+ if(!$targetpage) $targetpage = "/";
849
+
850
+ //other vars
851
+ $prev = $page - 1; //previous page is page - 1
852
+ $next = $page + 1; //next page is page + 1
853
+ $lastpage = ceil($totalitems / $limit); //lastpage is = total items / items per page, rounded up.
854
+ $lpm1 = $lastpage - 1; //last page minus 1
855
+
856
+ /*
857
+ Now we apply our rules and draw the pagination object.
858
+ We're actually saving the code to a variable in case we want to draw it more than once.
859
+ */
860
+ $pagination = "";
861
+ if($lastpage > 1)
862
+ {
863
+ $pagination .= "<div class=\"pmpro_pagination\"";
864
+ if(!empty($margin) || !empty($padding))
865
+ {
866
+ $pagination .= " style=\"";
867
+ if($margin)
868
+ $pagination .= "margin: $margin;";
869
+ if($padding)
870
+ $pagination .= "padding: $padding;";
871
+ $pagination .= "\"";
872
+ }
873
+ $pagination .= ">";
874
+
875
+ //previous button
876
+ if ($page > 1)
877
+ $pagination .= "<a href=\"$targetpage$pagestring$prev\">&laquo; prev</a>";
878
+ else
879
+ $pagination .= "<span class=\"disabled\">&laquo; prev</span>";
880
+
881
+ //pages
882
+ if ($lastpage < 7 + ($adjacents * 2)) //not enough pages to bother breaking it up
883
+ {
884
+ for ($counter = 1; $counter <= $lastpage; $counter++)
885
+ {
886
+ if ($counter == $page)
887
+ $pagination .= "<span class=\"current\">$counter</span>";
888
+ else
889
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
890
+ }
891
+ }
892
+ elseif($lastpage >= 7 + ($adjacents * 2)) //enough pages to hide some
893
+ {
894
+ //close to beginning; only hide later pages
895
+ if($page < 1 + ($adjacents * 3))
896
+ {
897
+ for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++)
898
+ {
899
+ if ($counter == $page)
900
+ $pagination .= "<span class=\"current\">$counter</span>";
901
+ else
902
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
903
+ }
904
+ $pagination .= "...";
905
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $lpm1 . "\">$lpm1</a>";
906
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $lastpage . "\">$lastpage</a>";
907
+ }
908
+ //in middle; hide some front and some back
909
+ elseif($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2))
910
+ {
911
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . "1\">1</a>";
912
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . "2\">2</a>";
913
+ $pagination .= "...";
914
+ for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++)
915
+ {
916
+ if ($counter == $page)
917
+ $pagination .= "<span class=\"current\">$counter</span>";
918
+ else
919
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
920
+ }
921
+ $pagination .= "...";
922
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $lpm1 . "\">$lpm1</a>";
923
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $lastpage . "\">$lastpage</a>";
924
+ }
925
+ //close to end; only hide early pages
926
+ else
927
+ {
928
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . "1\">1</a>";
929
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . "2\">2</a>";
930
+ $pagination .= "...";
931
+ for ($counter = $lastpage - (1 + ($adjacents * 3)); $counter <= $lastpage; $counter++)
932
+ {
933
+ if ($counter == $page)
934
+ $pagination .= "<span class=\"current\">$counter</span>";
935
+ else
936
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $counter . "\">$counter</a>";
937
+ }
938
+ }
939
+ }
940
+
941
+ //next button
942
+ if ($page < $counter - 1)
943
+ $pagination .= "<a href=\"" . $targetpage . $pagestring . $next . "\">next &raquo;</a>";
944
+ else
945
+ $pagination .= "<span class=\"disabled\">next &raquo;</span>";
946
+ $pagination .= "</div>\n";
947
+ }
948
+
949
+ return $pagination;
950
+
951
+ }
952
+
953
+ function pmpro_calculateInitialPaymentRevenue($s = NULL, $l = NULL)
954
+ {
955
+ global $wpdb;
956
+
957
+ //if we're limiting users by search
958
+ if($s || $l)
959
+ {
960
+ $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' ";
961
+ if($s)
962
+ $user_ids_query .= "AND (u.user_login LIKE '%$s%' OR u.user_email LIKE '%$s%' OR um.meta_value LIKE '%$s%') ";
963
+ if($l)
964
+ $user_ids_query .= "AND mu.membership_id = '$l' ";
965
+ }
966
+
967
+ //query to sum initial payments
968
+ $sqlQuery = "SELECT SUM(initial_payment) FROM $wpdb->pmpro_memberships_users WHERE `status` = 'active' ";
969
+ if(!empty($user_ids_query))
970
+ $sqlQuery .= "AND user_id IN(" . $user_ids_query . ") ";
971
+
972
+ $total = $wpdb->get_var($sqlQuery);
973
+
974
+ return (double)$total;
975
+ }
976
+
977
+ function pmpro_calculateRecurringRevenue($s, $l)
978
+ {
979
+ global $wpdb;
980
+
981
+ //if we're limiting users by search
982
+ if($s || $l)
983
+ {
984
+ $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' ";
985
+ if($s)
986
+ $user_ids_query .= "AND (u.user_login LIKE '%$s%' OR u.user_email LIKE '%$s%' OR um.meta_value LIKE '%$s%') ";
987
+ if($l)
988
+ $user_ids_query .= "AND mu.membership_id = '$l' ";
989
+ $user_ids_query .= ")";
990
+ }
991
+ else
992
+ $user_ids_query = "";
993
+
994
+ //4 queries to get annual earnings for each cycle period. currently ignoring trial periods and billing limits.
995
+ $sqlQuery = "
996
+ 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
997
+ UNION
998
+ 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
999
+ UNION
1000
+ 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
1001
+ UNION
1002
+ SELECT SUM(billing_amount) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND cycle_period = 'Year' $user_ids_query
1003
+ ";
1004
+
1005
+ $annual_revenues = $wpdb->get_col($sqlQuery);
1006
+
1007
+ $total = 0;
1008
+ foreach($annual_revenues as $r)
1009
+ {
1010
+ $total += $r;
1011
+ }
1012
+
1013
+ return $total;
1014
+ }
1015
+
1016
+ function pmpro_generateUsername($firstname = "", $lastname = "", $email = "")
1017
+ {
1018
+ global $wpdb;
1019
+
1020
+ //try first initial + last name, firstname, lastname
1021
+ $firstname = preg_replace("/[^A-Za-z]/", "", $firstname);
1022
+ $lastname = preg_replace("/[^A-Za-z]/", "", $lastname);
1023
+ if($firstname && $lastname)
1024
+ {
1025
+ $username = substr($firstname, 0, 1) . $lastname;
1026
+ }
1027
+ elseif($firstname)
1028
+ {
1029
+ $username = $firstname;
1030
+ }
1031
+ elseif($lastname)
1032
+ {
1033
+ $username = $lastname;
1034
+ }
1035
+
1036
+ //is it taken?
1037
+ $taken = $wpdb->get_var("SELECT user_login FROM $wpdb->users WHERE user_login = '" . $username . "' LIMIT 1");
1038
+
1039
+ if(!$taken)
1040
+ return $username;
1041
+
1042
+ //try the beginning of the email address
1043
+ $emailparts = explode("@", "email");
1044
+ if(is_array($emailparts))
1045
+ $email = preg_replace("/[^A-Za-z]/", "", $emailparts[0]);
1046
+
1047
+ if($email)
1048
+ {
1049
+ $username = $email;
1050
+ }
1051
+
1052
+ //is this taken? if not, add numbers until it works
1053
+ $taken = true;
1054
+ $count = 0;
1055
+ while($taken)
1056
+ {
1057
+ //add a # to the end
1058
+ if($count)
1059
+ {
1060
+ $username = preg_replace("/[0-9]/", "", $username) . $count;
1061
+ }
1062
+
1063
+ //taken?
1064
+ $taken = $wpdb->get_var("SELECT user_login FROM $wpdb->users WHERE user_login = '" . $username . "' LIMIT 1");
1065
+
1066
+ //increment the number
1067
+ $count++;
1068
+ }
1069
+
1070
+ //must have a good username now
1071
+ return $username;
1072
+ }
1073
+
1074
+ //get a new random code for discount codes
1075
+ function pmpro_getDiscountCode($seed = NULL)
1076
+ {
1077
+ global $wpdb;
1078
+
1079
+ while(empty($code))
1080
+ {
1081
+ $scramble = md5(AUTH_KEY . current_time('timestamp') . $seed . SECURE_AUTH_KEY);
1082
+ $code = substr($scramble, 0, 10);
1083
+ $check = $wpdb->get_var("SELECT code FROM $wpdb->pmpro_discount_codes WHERE code = '$code' LIMIT 1");
1084
+ if($check || is_numeric($code))
1085
+ $code = NULL;
1086
+ }
1087
+
1088
+ return strtoupper($code);
1089
+ }
1090
+
1091
+ //is a discount code valid
1092
+ function pmpro_checkDiscountCode($code, $level_id = NULL, $return_errors = false)
1093
+ {
1094
+ global $wpdb;
1095
+
1096
+ $error = false;
1097
+
1098
+ //no code, no code
1099
+ if(empty($code))
1100
+ $error = __("No code was given to check.", "pmpro");
1101
+
1102
+ //get code from db
1103
+ if(!$error)
1104
+ {
1105
+ $dbcode = $wpdb->get_row("SELECT *, UNIX_TIMESTAMP(starts) as starts, UNIX_TIMESTAMP(expires) as expires FROM $wpdb->pmpro_discount_codes WHERE code ='" . $code . "' LIMIT 1");
1106
+
1107
+ //did we find it?
1108
+ if(empty($dbcode->id))
1109
+ $error = __("The discount code could not be found.", "pmpro");
1110
+ }
1111
+
1112
+ //check if the code has started
1113
+ if(!$error)
1114
+ {
1115
+ //fix the date timestamps
1116
+ $dbcode->starts = strtotime(date("m/d/Y", $dbcode->starts));
1117
+ $dbcode->expires = strtotime(date("m/d/Y", $dbcode->expires));
1118
+
1119
+ //today
1120
+ $today = strtotime(date("m/d/Y 00:00:00", current_time("timestamp")));
1121
+
1122
+ //has this code started yet?
1123
+ if(!empty($dbcode->starts) && $dbcode->starts > $today)
1124
+ $error = sprintf(__("This discount code goes into effect on %s.", "pmpro"), date(get_option('date_format'), $dbcode->starts));
1125
+ }
1126
+
1127
+ //check if the code is expired
1128
+ if(!$error)
1129
+ {
1130
+ if(!empty($dbcode->expires) && $dbcode->expires < $today)
1131
+ $error = sprintf(__("This discount code expired on %s.", "pmpro"), date(get_option('date_format'), $dbcode->expires));
1132
+ }
1133
+
1134
+ //have we run out of uses?
1135
+ if(!$error)
1136
+ {
1137
+ if($dbcode->uses > 0)
1138
+ {
1139
+ $used = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->pmpro_discount_codes_uses WHERE code_id = '" . $dbcode->id . "'");
1140
+ if($used >= $dbcode->uses)
1141
+ $error = __("This discount code is no longer valid.", "pmpro");
1142
+ }
1143
+ }
1144
+
1145
+ //if a level was passed check if this code applies
1146
+ if(!$error)
1147
+ {
1148
+ $pmpro_check_discount_code_levels = apply_filters("pmpro_check_discount_code_levels", true, $dbcode->id);
1149
+ if(!empty($level_id) && $pmpro_check_discount_code_levels)
1150
+ {
1151
+ $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");
1152
+
1153
+ if(empty($code_level))
1154
+ $error = __("This discount code does not apply to this membership level.", "pmpro");
1155
+ }
1156
+ }
1157
+
1158
+ //allow filter
1159
+ $pmpro_check_discount_code = apply_filters("pmpro_check_discount_code", !$error, $dbcode, $level_id, $code);
1160
+ if(is_string($pmpro_check_discount_code))
1161
+ $error = $pmpro_check_discount_code; //string returned, this is an error
1162
+ elseif(!$pmpro_check_discount_code && !$error)
1163
+ $error = true; //no error before, but filter returned error
1164
+ elseif($pmpro_check_discount_code)
1165
+ $error = false; //filter is true, so error false
1166
+
1167
+ //return
1168
+ if($error)
1169
+ {
1170
+ //there was an error
1171
+ if(!empty($return_errors))
1172
+ return array(false, $error);
1173
+ else
1174
+ return false;
1175
+ }
1176
+ else
1177
+ {
1178
+ //guess we're all good
1179
+ if(!empty($return_errors))
1180
+ return array(true, __("This discount code is okay.", "pmpro"));
1181
+ else
1182
+ return true;
1183
+ }
1184
+ }
1185
+
1186
+ function pmpro_no_quotes($s, $quotes = array("'", '"'))
1187
+ {
1188
+ return str_replace($quotes, "", $s);
1189
+ }
1190
+
1191
+ //from: http://www.php.net/manual/en/function.implode.php#86845
1192
+ function pmpro_implodeToEnglish($array)
1193
+ {
1194
+ // sanity check
1195
+ if (!$array || !count ($array))
1196
+ return '';
1197
+
1198
+ // get last element
1199
+ $last = array_pop ($array);
1200
+
1201
+ // if it was the only element - return it
1202
+ if (!count ($array))
1203
+ return $last;
1204
+
1205
+ return implode (', ', $array).' ' . __('and', 'pmpro') . ' '.$last;
1206
+ }
1207
+
1208
+ //from yoast wordpress seo
1209
+ function pmpro_text_limit( $text, $limit, $finish = '&hellip;')
1210
+ {
1211
+ if( strlen( $text ) > $limit ) {
1212
+ $text = substr( $text, 0, $limit );
1213
+ $text = substr( $text, 0, - ( strlen( strrchr( $text,' ') ) ) );
1214
+ $text .= $finish;
1215
+ }
1216
+ return $text;
1217
+ }
1218
+
1219
+ /* pmpro_getMembershipLevelForUser() returns the first active membership level for a user
1220
+ *
1221
+ * If $user_id is omitted, the value will be retrieved from $current_user.
1222
+ *
1223
+ * Return values:
1224
+ * Success returns the level object.
1225
+ * Failure returns false.
1226
+ */
1227
+ function pmpro_getMembershipLevelForUser($user_id = NULL, $force = false)
1228
+ {
1229
+ if(empty($user_id))
1230
+ {
1231
+ global $current_user;
1232
+ $user_id = $current_user->ID;
1233
+ }
1234
+
1235
+ if(empty($user_id))
1236
+ {
1237
+ return false;
1238
+ }
1239
+
1240
+ global $all_membership_levels;
1241
+
1242
+ if(isset($all_membership_levels[$user_id]) && !$force)
1243
+ {
1244
+ return $all_membership_levels[$user_id];
1245
+ }
1246
+ else
1247
+ {
1248
+ global $wpdb;
1249
+ $all_membership_levels[$user_id] = $wpdb->get_row("SELECT
1250
+ l.id AS ID,
1251
+ l.id as id,
1252
+ mu.id as subscription_id,
1253
+ l.name AS name,
1254
+ l.description,
1255
+ l.expiration_number,
1256
+ l.expiration_period,
1257
+ mu.initial_payment,
1258
+ mu.billing_amount,
1259
+ mu.cycle_number,
1260
+ mu.cycle_period,
1261
+ mu.billing_limit,
1262
+ mu.trial_amount,
1263
+ mu.trial_limit,
1264
+ mu.code_id as code_id,
1265
+ UNIX_TIMESTAMP(startdate) as startdate,
1266
+ UNIX_TIMESTAMP(enddate) as enddate
1267
+ FROM {$wpdb->pmpro_membership_levels} AS l
1268
+ JOIN {$wpdb->pmpro_memberships_users} AS mu ON (l.id = mu.membership_id)
1269
+ WHERE mu.user_id = $user_id AND mu.status = 'active'
1270
+ LIMIT 1");
1271
+ return $all_membership_levels[$user_id];
1272
+ }
1273
+ }
1274
+
1275
+ /* pmpro_getMembershipLevelsForUser() returns the membership levels for a user
1276
+ *
1277
+ * If $user_id is omitted, the value will be retrieved from $current_user.
1278
+ * By default it only includes actvie memberships.
1279
+ *
1280
+ * Return values:
1281
+ * Success returns an array of level objects.
1282
+ * Failure returns false.
1283
+ */
1284
+ function pmpro_getMembershipLevelsForUser($user_id = NULL, $include_inactive = false)
1285
+ {
1286
+ if(empty($user_id))
1287
+ {
1288
+ global $current_user;
1289
+ $user_id = $current_user->ID;
1290
+ }
1291
+
1292
+ if(empty($user_id))
1293
+ {
1294
+ return false;
1295
+ }
1296
+
1297
+ global $wpdb;
1298
+ return $wpdb->get_results("SELECT
1299
+ l.id AS ID,
1300
+ l.id as id,
1301
+ mu.id as subscription_id,
1302
+ l.name,
1303
+ l.description,
1304
+ l.expiration_number,
1305
+ l.expiration_period,
1306
+ mu.initial_payment,
1307
+ mu.billing_amount,
1308
+ mu.cycle_number,
1309
+ mu.cycle_period,
1310
+ mu.billing_limit,
1311
+ mu.trial_amount,
1312
+ mu.trial_limit,
1313
+ mu.code_id as code_id,
1314
+ UNIX_TIMESTAMP(startdate) as startdate,
1315
+ UNIX_TIMESTAMP(enddate) as enddate
1316
+ FROM {$wpdb->pmpro_membership_levels} AS l
1317
+ JOIN {$wpdb->pmpro_memberships_users} AS mu ON (l.id = mu.membership_id)
1318
+ WHERE mu.user_id = $user_id".($include_inactive?"":" AND mu.status = 'active'"));
1319
+ }
1320
+
1321
+ /* pmpro_getLevel() returns the level object for a level
1322
+ *
1323
+ * $level may be the level id or name
1324
+ *
1325
+ * Return values:
1326
+ * Success returns the level object.
1327
+ * Failure returns false.
1328
+ */
1329
+ function pmpro_getLevel($level)
1330
+ {
1331
+ global $pmpro_levels;
1332
+
1333
+ if(is_object($level) && !empty($level->id))
1334
+ $level = $level->id;
1335
+
1336
+ //was a name passed? (Todo: make sure level names have at least one non-numeric character.
1337
+ if(is_numeric($level))
1338
+ {
1339
+ $level_id = intval($level);
1340
+ if(isset($pmpro_levels[$level_id]))
1341
+ {
1342
+ return $pmpro_levels[$level_id];
1343
+ }
1344
+ else
1345
+ {
1346
+ global $wpdb;
1347
+ $pmpro_levels[$level_id] = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . $level_id . "' LIMIT 1");
1348
+ return $pmpro_levels[$level_id];
1349
+ }
1350
+ }
1351
+ else
1352
+ {
1353
+ global $wpdb;
1354
+ $level_obj = $wpdb->get_row("SELECT * FROM $wpdb->pmpro_membership_levels WHERE name = '" . $level . "' LIMIT 1");
1355
+ $level_id = $level_obj->id;
1356
+ $pmpro_levels[$level_id] = $level_obj;
1357
+ return $pmpro_levels[$level_id];
1358
+ }
1359
+ }
1360
+
1361
+ /*
1362
+ Function to populate pmpro_levels with all levels. We query the DB every time just to be sure we have the latest.
1363
+ This should be called if you want to be sure you get all levels as $pmpro_levels may only have a subset of levels.
1364
+ */
1365
+ function pmpro_getAllLevels($include_hidden = false, $force = false)
1366
+ {
1367
+ global $pmpro_levels, $wpdb;
1368
+
1369
+ //just use what's cached (doesn't take into account include_hidden setting)
1370
+ if(!empty($pmpro_levels) && !$force)
1371
+ return $pmpro_levels;
1372
+
1373
+ //build query
1374
+ $sqlQuery = "SELECT * FROM $wpdb->pmpro_membership_levels ";
1375
+ if(!$include_hidden)
1376
+ $sqlQuery .= " WHERE allow_signups = 1 ORDER BY id";
1377
+
1378
+ //get levels from the DB
1379
+ $raw_levels = $wpdb->get_results($sqlQuery);
1380
+
1381
+ //lets put them into an array where the key is the id of the level
1382
+ $pmpro_levels = array();
1383
+ foreach($raw_levels as $raw_level)
1384
+ {
1385
+ $pmpro_levels[$raw_level->id] = $raw_level;
1386
+ }
1387
+
1388
+ return $pmpro_levels;
1389
+ }
1390
+
1391
+ function pmpro_getCheckoutButton($level_id, $button_text = NULL, $classes = NULL)
1392
+ {
1393
+ if(empty($button_text))
1394
+ $button_text = __("Sign Up for !!name!! Now", "pmpro");
1395
+
1396
+ if(empty($classes))
1397
+ $classes = "pmpro_btn";
1398
+
1399
+ if(empty($level_id))
1400
+ $r = __("Please specify a level id.", "pmpro");
1401
+ else
1402
+ {
1403
+ //get level
1404
+ $level = pmpro_getLevel($level_id);
1405
+
1406
+ //replace vars
1407
+ $replacements = array(
1408
+ "!!id!!" => $level->id,
1409
+ "!!name!!" => $level->name,
1410
+ "!!description!!" => $level->description,
1411
+ "!!confirmation!!" => $level->confirmation,
1412
+ "!!initial_payment!!" => $level->initial_payment,
1413
+ "!!billing_amount!!" => $level->billing_amount,
1414
+ "!!cycle_number!!" => $level->cycle_number,
1415
+ "!!cycle_period!!" => $level->cycle_period,
1416
+ "!!billing_limit!!" => $level->billing_limit,
1417
+ "!!trial_amount!!" => $level->trial_amount,
1418
+ "!!trial_limit!!" => $level->trial_limit,
1419
+ "!!expiration_number!!" => $level->expiration_number,
1420
+ "!!expiration_period!!" => $level->expiration_period
1421
+ );
1422
+ $button_text = str_replace(array_keys($replacements), $replacements, $button_text);
1423
+
1424
+ //button text
1425
+ $r = "<a href=\"" . pmpro_url("checkout", "?level=" . $level_id) . "\" class=\"" . $classes . "\">" . $button_text . "</a>";
1426
+ }
1427
+ return $r;
1428
+ }
1429
+
1430
+ /**
1431
+ * Get the "domain" from a URL. By domain, we mean the host name, minus any subdomains. So just the domain and TLD.
1432
+ *
1433
+ * @param string $url The URL to parse. (generally pass site_url() in WP)
1434
+ * @return string The domain.
1435
+ */
1436
+ function pmpro_getDomainFromURL($url = NULL)
1437
+ {
1438
+ $domainparts = parse_url($url);
1439
+ $domainparts = explode(".", $domainparts['host']);
1440
+ if(count($domainparts) > 1)
1441
+ {
1442
+ //check for ips
1443
+ $isip = true;
1444
+ foreach($domainparts as $part)
1445
+ {
1446
+ if(!is_numeric($part))
1447
+ {
1448
+ $isip = false;
1449
+ break;
1450
+ }
1451
+ }
1452
+
1453
+ if($isip)
1454
+ {
1455
+ //ip, e.g. 127.1.1.1
1456
+ $domain = implode(".", $domainparts);
1457
+ }
1458
+ else
1459
+ {
1460
+ //www.something.com, etc.
1461
+ $domain = $domainparts[count($domainparts)-2] . "." . $domainparts[count($domainparts)-1];
1462
+ }
1463
+ }
1464
+ else
1465
+ {
1466
+ //localhost or another single word domain
1467
+ $domain = $domainparts[0];
1468
+ }
1469
+
1470
+ return $domain;
1471
+ }
1472
+
1473
+ /*
1474
+ Get a member's start date... either in general or for a specific level_id.
1475
+ */
1476
+ if(!function_exists("pmpro_getMemberStartdate"))
1477
+ {
1478
+ function pmpro_getMemberStartdate($user_id = NULL, $level_id = 0)
1479
+ {
1480
+ if(empty($user_id))
1481
+ {
1482
+ global $current_user;
1483
+ $user_id = $current_user->ID;
1484
+ }
1485
+
1486
+ global $pmpro_startdates; //for cache
1487
+ if(empty($pmpro_startdates[$user_id][$level_id]))
1488
+ {
1489
+ global $wpdb;
1490
+
1491
+ if(!empty($level_id))
1492
+ $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";
1493
+ else
1494
+ $sqlQuery = "SELECT UNIX_TIMESTAMP(startdate) FROM $wpdb->pmpro_memberships_users WHERE status = 'active' AND user_id = '" . $user_id . "' ORDER BY id LIMIT 1";
1495
+
1496
+ $startdate = apply_filters("pmpro_member_startdate", $wpdb->get_var($sqlQuery), $user_id, $level_id);
1497
+
1498
+ $pmpro_startdates[$user_id][$level_id] = $startdate;
1499
+ }
1500
+
1501
+ return $pmpro_startdates[$user_id][$level_id];
1502
+ }
1503
+ }
1504
+
1505
+ /*
1506
+ How long has this member been a member
1507
+ */
1508
+ if(!function_exists("pmpro_getMemberDays"))
1509
+ {
1510
+ function pmpro_getMemberDays($user_id = NULL, $level_id = 0)
1511
+ {
1512
+ if(empty($user_id))
1513
+ {
1514
+ global $current_user;
1515
+ $user_id = $current_user->ID;
1516
+ }
1517
+
1518
+ global $pmpro_member_days;
1519
+ if(empty($pmpro_member_days[$user_id][$level_id]))
1520
+ {
1521
+ $startdate = pmpro_getMemberStartdate($user_id, $level_id);
1522
+
1523
+ //check that there was a startdate at all
1524
+ if(empty($startdate))
1525
+ $pmpro_member_days[$user_id][$level_id] = 0;
1526
+ else
1527
+ {
1528
+ $now = current_time('timestamp');
1529
+ $days = ($now - $startdate)/3600/24;
1530
+
1531
+ $pmpro_member_days[$user_id][$level_id] = $days;
1532
+ }
1533
+ }
1534
+
1535
+ return $pmpro_member_days[$user_id][$level_id];
1536
+ }
1537
+ }
1538
+
1539
+ //the start of a message handling script
1540
+ function pmpro_setMessage($message, $type, $force = false)
1541
+ {
1542
+ global $pmpro_msg, $pmpro_msgt;
1543
+
1544
+ //for now, we only show the first message generated
1545
+ if($force || empty($pmpro_msg))
1546
+ {
1547
+ $pmpro_msg = $message;
1548
+ $pmpro_msgt = $type;
1549
+ }
1550
+ }
1551
+
1552
+ //used in class definitions for input fields to see if there was an error
1553
+ function pmpro_getClassForField($field)
1554
+ {
1555
+ global $pmpro_error_fields, $pmpro_required_billing_fields, $pmpro_required_user_fields;
1556
+ $classes = array();
1557
+
1558
+ //error on this field?
1559
+ if(!empty($pmpro_error_fields) && in_array($field, $pmpro_error_fields))
1560
+ {
1561
+ $classes[] = "pmpro_error";
1562
+ }
1563
+
1564
+ if(is_array($pmpro_required_billing_fields) && is_array($pmpro_required_user_fields))
1565
+ $required_fields = array_merge(array_keys($pmpro_required_billing_fields), array_keys($pmpro_required_user_fields));
1566
+ elseif(is_array($pmpro_required_billing_fields))
1567
+ $required_fields = array_keys($pmpro_required_billing_fields);
1568
+ elseif(is_array($pmpro_required_user_fields))
1569
+ $required_fields = array_keys($pmpro_required_user_fields);
1570
+ else
1571
+ $required_fields = array();
1572
+
1573
+ //required?
1574
+ if(in_array($field, $required_fields))
1575
+ {
1576
+ $classes[] = "pmpro_required";
1577
+ }
1578
+
1579
+ $classes = apply_filters("pmpro_field_classes", $classes, $field);
1580
+
1581
+ if(!empty($classes))
1582
+ return implode(" ", $classes);
1583
+ else
1584
+ return "";
1585
+ }
1586
+
1587
+ //get a var from $_GET or $_POST
1588
+ function pmpro_getParam($index, $method = "REQUEST", $default = "")
1589
+ {
1590
+ if($method == "REQUEST")
1591
+ {
1592
+ if(!empty($_REQUEST[$index]))
1593
+ return $_REQUEST[$index];
1594
+ }
1595
+ elseif($method == "POST")
1596
+ {
1597
+ if(!empty($_POST[$index]))
1598
+ return $_POST[$index];
1599
+ }
1600
+ elseif($method == "GET")
1601
+ {
1602
+ if(!empty($_GET[$index]))
1603
+ return $_GET[$index];
1604
+ }
1605
+
1606
+ return $default;
1607
+ }
1608
+
1609
+ /*
1610
+ Format an address from address, city, state, zip, country, and phone
1611
+ */
1612
+ function pmpro_formatAddress($name, $address1, $address2, $city, $state, $zip, $country, $phone, $nl2br = true)
1613
+ {
1614
+ $address = "";
1615
+
1616
+ if(!empty($name))
1617
+ $address .= $name . "\n";
1618
+
1619
+ if(!empty($address1))
1620
+ $address .= $address1 . "\n";
1621
+
1622
+ if(!empty($address2))
1623
+ $address .= $address2 . "\n";
1624
+
1625
+ if(!empty($city) && !empty($state))
1626
+ {
1627
+ $address .= $city . ", " . $state;
1628
+
1629
+ if(!empty($zip))
1630
+ $address .= " " . $zip;
1631
+
1632
+ $address .= "\n";
1633
+ }
1634
+
1635
+ if(!empty($country))
1636
+ $address .= $country . "\n";
1637
+
1638
+ if(!empty($phone))
1639
+ $address .= formatPhone($phone);
1640
+
1641
+ if($nl2br)
1642
+ $address = nl2br($address);
1643
+
1644
+ return $address;
1645
+ }
1646
+
1647
+ /*
1648
+ Checks if all required settings are set.
1649
+ */
1650
+ function pmpro_is_ready()
1651
+ {
1652
+ global $wpdb, $pmpro_pages, $pmpro_level_ready, $pmpro_gateway_ready, $pmpro_pages_ready;
1653
+
1654
+ //check if there is at least one level
1655
+ $pmpro_level_ready = (bool)$wpdb->get_var("SELECT id FROM $wpdb->pmpro_membership_levels LIMIT 1");
1656
+
1657
+ //check if the gateway settings are good. first check if it's needed (is there paid membership level)
1658
+ $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");
1659
+ $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");
1660
+
1661
+ if(empty($paid_membership_level) && empty($paid_user_subscription))
1662
+ {
1663
+ //no paid membership level now or attached to a user. we don't need the gateway setup
1664
+ $pmpro_gateway_ready = true;
1665
+ }
1666
+ else
1667
+ {
1668
+ $gateway = pmpro_getOption("gateway");
1669
+ if($gateway == "authorizenet")
1670
+ {
1671
+ if(pmpro_getOption("gateway_environment") && pmpro_getOption("loginname") && pmpro_getOption("transactionkey"))
1672
+ $pmpro_gateway_ready = true;
1673
+ else
1674
+ $pmpro_gateway_ready = false;
1675
+ }
1676
+ elseif($gateway == "paypal" || $gateway == "paypalexpress")
1677
+ {
1678
+ if(pmpro_getOption("gateway_environment") && pmpro_getOption("gateway_email") && pmpro_getOption("apiusername") && pmpro_getOption("apipassword") && pmpro_getOption("apisignature"))
1679
+ $pmpro_gateway_ready = true;
1680
+ else
1681
+ $pmpro_gateway_ready = false;
1682
+ }
1683
+ elseif($gateway == "paypalstandard")
1684
+ {
1685
+ if(pmpro_getOption("gateway_environment") && pmpro_getOption("gateway_email"))
1686
+ $pmpro_gateway_ready = true;
1687
+ else
1688
+ $pmpro_gateway_ready = false;
1689
+ }
1690
+ elseif($gateway == "payflowpro")
1691
+ {
1692
+ if(pmpro_getOption("payflow_partner") && pmpro_getOption("payflow_vendor") && pmpro_getOption("payflow_user") && pmpro_getOption("payflow_pwd"))
1693
+ $pmpro_gateway_ready = true;
1694
+ else
1695
+ $pmpro_gateway_ready = false;
1696
+ }
1697
+ elseif($gateway == "stripe")
1698
+ {
1699
+ if(pmpro_getOption("gateway_environment") && pmpro_getOption("stripe_secretkey") && pmpro_getOption("stripe_publishablekey"))
1700
+ $pmpro_gateway_ready = true;
1701
+ else
1702
+ $pmpro_gateway_ready = false;
1703
+ }
1704
+ elseif($gateway == "braintree")
1705
+ {
1706
+ if(pmpro_getOption("gateway_environment") && pmpro_getOption("braintree_merchantid") && pmpro_getOption("braintree_publickey") && pmpro_getOption("braintree_privatekey"))
1707
+ $pmpro_gateway_ready = true;
1708
+ else
1709
+ $pmpro_gateway_ready = false;
1710
+ }
1711
+ elseif($gateway == "twocheckout")
1712
+ {
1713
+ if(pmpro_getOption("gateway_environment") && pmpro_getOption("twocheckout_apiusername") && pmpro_getOption("twocheckout_apipassword"))
1714
+ $pmpro_gateway_ready = true;
1715
+ else
1716
+ $pmpro_gateway_ready = false;
1717
+ }
1718
+ elseif($gateway == "cybersource")
1719
+ {
1720
+ if(pmpro_getOption("gateway_environment") && pmpro_getOption("cybersource_merchantid") && pmpro_getOption("cybersource_securitykey"))
1721
+ $pmpro_gateway_ready = true;
1722
+ else
1723
+ $pmpro_gateway_ready = false;
1724
+ }
1725
+ else
1726
+ {
1727
+ $pmpro_gateway_ready = false;
1728
+ }
1729
+ }
1730
+
1731
+ //check if we have all pages
1732
+ if($pmpro_pages["account"] &&
1733
+ $pmpro_pages["billing"] &&
1734
+ $pmpro_pages["cancel"] &&
1735
+ $pmpro_pages["checkout"] &&
1736
+ $pmpro_pages["confirmation"] &&
1737
+ $pmpro_pages["invoice"] &&
1738
+ $pmpro_pages["levels"])
1739
+ $pmpro_pages_ready = true;
1740
+ else
1741
+ $pmpro_pages_ready = false;
1742
+
1743
+ //now check both
1744
+ if($pmpro_gateway_ready && $pmpro_pages_ready)
1745
+ return true;
1746
+ else
1747
+ return false;
1748
+ }
1749
+
1750
+ /**
1751
+ * Format a price per the currency settings.
1752
+ *
1753
+ * @since 1.7.15
1754
+ */
1755
+ function pmpro_formatPrice($price)
1756
+ {
1757
+ global $pmpro_currency, $pmpro_currency_symbol, $pmpro_currencies;
1758
+
1759
+ //start with the price formatted with two decimals
1760
+ $formatted = number_format($price, 2);
1761
+
1762
+ //settings stored in array?
1763
+ if(!empty($pmpro_currencies[$pmpro_currency]) && is_array($pmpro_currencies[$pmpro_currency]))
1764
+ {
1765
+ //which side is the symbol on?
1766
+ if(!empty($pmpro_currencies[$pmpro_currency]['position']) && $pmpro_currencies[$pmpro_currency]['position']== 'left')
1767
+ $formatted = $pmpro_currency_symbol . $formatted;
1768
+ else
1769
+ $formatted = $formatted . $pmpro_currency_symbol;
1770
+
1771
+ //commas or periods?
1772
+ if(!empty($pmpro_currencies[$pmpro_currency]['separator']) && $pmpro_currencies[$pmpro_currency]['separator'])
1773
+ $formatted = str_replace(array(".",","), $pmpro_currencies[$pmpro_currency]['separator'], $formatted);
1774
+ }
1775
+ else
1776
+ $formatted = $pmpro_currency_symbol . $formatted; //default to symbol on the left
1777
+
1778
+ //filter
1779
+ return apply_filters('pmpro_format_price', $formatted, $price, $pmpro_currency, $pmpro_currency_symbol);
1780
+ }
1781
+
1782
+ /**
1783
+ * Which side does the currency symbol go on?
1784
+ *
1785
+ * @since 1.7.15
1786
+ */
1787
+ function pmpro_getCurrencyPosition()
1788
+ {
1789
+ global $pmpro_currency, $pmpro_currencies;
1790
+
1791
+ if(!empty($pmpro_currencies[$pmpro_currency]) && is_array($pmpro_currencies[$pmpro_currency]) && !empty($pmpro_currencies[$pmpro_currency]['position']))
1792
+ return $pmpro_currencies[$pmpro_currency]['position'];
1793
+ else
1794
+ return "left";
1795
+ }
includes/https.php ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Code related to HTTPS/SSL
4
+ */
5
+
6
+ //this function checks if we have set the $isapage variable, and if so prevents WP from sending a 404
7
+ function pmpro_status_filter($s)
8
+ {
9
+ global $isapage;
10
+ if($isapage && strpos($s, "404"))
11
+ return false; //don't send the 404
12
+ else
13
+ return $s;
14
+ }
15
+
16
+ //filters links/etc to add HTTPS to URL if needed
17
+ function pmpro_https_filter($s)
18
+ {
19
+ global $besecure;
20
+ $besecure = apply_filters('pmpro_besecure', $besecure);
21
+
22
+ if($besecure || is_ssl())
23
+ return str_replace("http:", "https:", $s);
24
+ else
25
+ return str_replace("https:", "http:", $s);
26
+ }
27
+ add_filter('status_header', 'pmpro_status_filter');
28
+ add_filter('bloginfo_url', 'pmpro_https_filter');
29
+ add_filter('wp_list_pages', 'pmpro_https_filter');
30
+ add_filter('option_home', 'pmpro_https_filter');
31
+ add_filter('option_siteurl', 'pmpro_https_filter');
32
+ add_filter('logout_url', 'pmpro_https_filter');
33
+ add_filter('login_url', 'pmpro_https_filter');
34
+ add_filter('home_url', 'pmpro_https_filter');
35
+
36
+ //this function sets the besecure global which may be used in early code
37
+ /*
38
+ function pmpro_besecure_set()
39
+ {
40
+ global $besecure;
41
+ if(force_ssl_admin() || force_ssl_login() || is_ssl())
42
+ $besecure = true;
43
+
44
+ $besecure = apply_filters("pmpro_besecure", $besecure);
45
+ }
46
+ add_action('init', 'pmpro_besecure_set', 2);
47
+ */
48
+
49
+ //this function updates the besecure global with post data and redirects if needed
50
+ function pmpro_besecure()
51
+ {
52
+ global $besecure, $post;
53
+
54
+ //check the post option
55
+ if(!is_admin() && !empty($post->ID) && !$besecure)
56
+ $besecure = get_post_meta($post->ID, "besecure", true);
57
+
58
+ //if forcing ssl on admin, be secure in admin and login page
59
+ if(!$besecure && force_ssl_admin() && (is_admin() || pmpro_is_login_page()))
60
+ $besecure = true;
61
+
62
+ //if forcing ssl on login, be secure on the login page
63
+ if(!$besecure && force_ssl_login() && pmpro_is_login_page())
64
+ $besecure = true;
65
+
66
+ $besecure = apply_filters("pmpro_besecure", $besecure);
67
+
68
+ $use_ssl = pmpro_getOption("use_ssl");
69
+ if($use_ssl == 1)
70
+ {
71
+ if($besecure && (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == "off" || $_SERVER['HTTPS'] == "false"))
72
+ {
73
+ //need to be secure
74
+ wp_redirect("https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
75
+ exit;
76
+ }
77
+ elseif(!$besecure && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != "off" && $_SERVER['HTTPS'] != "false")
78
+ {
79
+ //don't need to be secure
80
+ wp_redirect("http://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
81
+ exit;
82
+ }
83
+ }
84
+ }
85
+ add_action('wp', 'pmpro_besecure', 2);
86
+ add_action('login_init', 'pmpro_besecure', 2);
87
+
88
+ //JavaScript SSL redirect
89
+ function pmpro_ssl_javascript_redirect()
90
+ {
91
+ global $besecure;
92
+ $use_ssl = pmpro_getOption("use_ssl");
93
+ if(!is_admin() && $use_ssl == 2)
94
+ {
95
+ if($besecure)
96
+ {
97
+ ?>
98
+ <script lang="JavaScript">
99
+ //needs to be secure
100
+ if (window.location.protocol != "https:")
101
+ window.location.href = "https:" + window.location.href.substring(window.location.protocol.length);
102
+ </script>
103
+ <?php
104
+ }
105
+ else
106
+ {
107
+ ?>
108
+ <script lang="JavaScript">
109
+ //should be over http
110
+ if (window.location.protocol != "http:")
111
+ window.location.href = "http:" + window.location.href.substring(window.location.protocol.length);
112
+ </script>
113
+ <?php
114
+ }
115
+ }
116
+ }
117
+ add_action('wp_print_scripts', 'pmpro_ssl_javascript_redirect');
118
+
119
+ //If the site URL starts with https:, then force SSL/besecure to true. (Added 1.5.2)
120
+ function pmpro_check_site_url_for_https($besecure)
121
+ {
122
+ global $wpdb, $pmpro_siteurl;
123
+
124
+ //need to get this from the database because we filter get_option
125
+ if(empty($pmpro_siteurl))
126
+ $pmpro_siteurl = $wpdb->get_var("SELECT option_value FROM $wpdb->options WHERE option_name = 'siteurl' LIMIT 1");
127
+
128
+ //entire site is over https?
129
+ if(strpos($pmpro_siteurl, "https:") !== false)
130
+ $besecure = true;
131
+
132
+ return $besecure;
133
+ }
134
+ add_filter("pmpro_besecure", "pmpro_check_site_url_for_https");
135
+
136
+ //capturing case where a user links to https admin without admin over https
137
+ function pmpro_admin_https_handler()
138
+ {
139
+ if(!empty($_SERVER['HTTPS']))
140
+ {
141
+ if($_SERVER['HTTPS'] && $_SERVER['HTTPS'] != "off" && $_SERVER['HTTPS'] != "false" && is_admin())
142
+ {
143
+ if(substr(get_option("siteurl"), 0, 5) == "http:" && !force_ssl_admin())
144
+ {
145
+ //need to redirect to non https
146
+ wp_redirect("http://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
147
+ exit;
148
+ }
149
+ }
150
+ }
151
+ }
152
+ add_action('init', 'pmpro_admin_https_handler');
153
+
154
+ /*
155
+ This code is for the "nuke" option to make URLs secure on secure pages.
156
+ */
157
+ function pmpro_NuclearHTTPS()
158
+ {
159
+ //did they choose the option?
160
+ $nuking = pmpro_getOption("nuclear_HTTPS");
161
+ if(!empty($nuking))
162
+ {
163
+ ob_start("pmpro_replaceURLsInBuffer");
164
+ }
165
+ }
166
+ add_action("init", "pmpro_NuclearHTTPS");
167
+
168
+ function pmpro_replaceURLsInBuffer($buffer)
169
+ {
170
+ global $besecure;
171
+
172
+ //only swap URLs if this page is secure
173
+ if($besecure)
174
+ {
175
+ /*
176
+ okay swap out all links like these:
177
+ * http://domain.com
178
+ * http://anysubdomain.domain.com
179
+ * http://any.number.of.sub.domains.domain.com
180
+ */
181
+ $buffer = preg_replace("/http\:\/\/([a-zA-Z0-9\.\-]*" . str_replace(".", "\.", PMPRO_DOMAIN) . ")/i", "https://$1", $buffer);
182
+ }
183
+
184
+ return $buffer;
185
+ }
includes/init.php ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Code that runs on the init, set_current_user, or wp hooks to setup PMPro
4
+ */
5
+ //init code
6
+ function pmpro_init()
7
+ {
8
+ require_once(PMPRO_DIR . "/includes/countries.php");
9
+ require_once(PMPRO_DIR . "/includes/states.php");
10
+ require_once(PMPRO_DIR . "/includes/currencies.php");
11
+
12
+ wp_enqueue_script('ssmemberships_js', plugins_url('js/paid-memberships-pro.js',dirname(__FILE__) ), array('jquery'));
13
+
14
+ if(is_admin())
15
+ {
16
+ $admin_css_rtl = false;
17
+ if(file_exists(get_stylesheet_directory() . "/paid-memberships-pro/css/admin.css")) {
18
+ $admin_css = get_stylesheet_directory_uri() . "/paid-memberships-pro/css/admin.css";
19
+ if( is_rtl() && file_exists(get_stylesheet_directory() . "/paid-memberships-pro/css/admin-rtl.css") ) {
20
+ $admin_css_rtl = get_stylesheet_directory_uri() . "/paid-memberships-pro/css/admin-rtl.css";
21
+ }
22
+ } elseif(file_exists(get_template_directory() . "/paid-memberships-pro/admin.css")) {
23
+ $admin_css = get_template_directory_uri() . "/paid-memberships-pro/admin.css";
24
+ if( is_rtl() && file_exists(get_template_directory() . "/paid-memberships-pro/css/admin-rtl.css") ) {
25
+ $admin_css_rtl = get_template_directory_uri() . "/paid-memberships-pro/css/admin-rtl.css";
26
+ }
27
+ } else {
28
+ $admin_css = plugins_url('css/admin.css',dirname(__FILE__) );
29
+ if( is_rtl() ) {
30
+ $admin_css_rtl = plugins_url('css/admin-rtl.css',dirname(__FILE__) );
31
+ }
32
+ }
33
+ wp_enqueue_style('pmpro_admin', $admin_css, array(), PMPRO_VERSION, "screen");
34
+ if( $admin_css_rtl ) {
35
+ wp_enqueue_style('pmpro_admin_rtl', $admin_css_rtl, array(), PMPRO_VERSION, "screen");
36
+ }
37
+ }
38
+ else
39
+ {
40
+ $frontend_css_rtl = false;
41
+ if(file_exists(get_stylesheet_directory() . "/paid-memberships-pro/css/frontend.css")) {
42
+ $frontend_css = get_stylesheet_directory_uri() . "/paid-memberships-pro/css/frontend.css";
43
+ if( is_rtl() && file_exists(get_stylesheet_directory() . "/paid-memberships-pro/css/frontend-rtl.css") ) {
44
+ $frontend_css_rtl = get_stylesheet_directory_uri() . "/paid-memberships-pro/css/frontend-rtl.css";
45
+ }
46
+ } elseif(file_exists(get_template_directory() . "/paid-memberships-pro/frontend.css")) {
47
+ $frontend_css = get_template_directory_uri() . "/paid-memberships-pro/frontend.css";
48
+ if( is_rtl() && file_exists(get_template_directory() . "/paid-memberships-pro/css/frontend-rtl.css") ) {
49
+ $frontend_css_rtl = get_template_directory_uri() . "/paid-memberships-pro/css/frontend-rtl.css";
50
+ }
51
+ } else {
52
+ $frontend_css = plugins_url('css/frontend.css',dirname(__FILE__) );
53
+ if( is_rtl() ) {
54
+ $frontend_css_rtl = plugins_url('css/frontend-rtl.css',dirname(__FILE__) );
55
+ }
56
+ }
57
+ wp_enqueue_style('pmpro_frontend', $frontend_css, array(), PMPRO_VERSION, "screen");
58
+ if( $frontend_css_rtl ) {
59
+ wp_enqueue_style('pmpro_frontend_rtl', $frontend_css_rtl, array(), PMPRO_VERSION, "screen");
60
+ }
61
+
62
+ if(file_exists(get_stylesheet_directory() . "/paid-memberships-pro/css/print.css"))
63
+ $print_css = get_stylesheet_directory_uri() . "/paid-memberships-pro/css/print.css";
64
+ elseif(file_exists(get_template_directory() . "/paid-memberships-pro/print.css"))
65
+ $print_css = get_template_directory_uri() . "/paid-memberships-pro/print.css";
66
+ else
67
+ $print_css = plugins_url('css/print.css',dirname(__FILE__) );
68
+ wp_enqueue_style('pmpro_print', $print_css, array(), PMPRO_VERSION, "print");
69
+ }
70
+
71
+ global $pmpro_pages, $pmpro_ready, $pmpro_currencies, $pmpro_currency, $pmpro_currency_symbol;
72
+ $pmpro_pages = array();
73
+ $pmpro_pages["account"] = pmpro_getOption("account_page_id");
74
+ $pmpro_pages["billing"] = pmpro_getOption("billing_page_id");
75
+ $pmpro_pages["cancel"] = pmpro_getOption("cancel_page_id");
76
+ $pmpro_pages["checkout"] = pmpro_getOption("checkout_page_id");
77
+ $pmpro_pages["confirmation"] = pmpro_getOption("confirmation_page_id");
78
+ $pmpro_pages["invoice"] = pmpro_getOption("invoice_page_id");
79
+ $pmpro_pages["levels"] = pmpro_getOption("levels_page_id");
80
+
81
+ $pmpro_ready = pmpro_is_ready();
82
+
83
+ //set currency
84
+ $pmpro_currency = pmpro_getOption("currency");
85
+ if(!$pmpro_currency)
86
+ {
87
+ global $pmpro_default_currency;
88
+ $pmpro_currency = $pmpro_default_currency;
89
+ }
90
+
91
+ //figure out what symbol to show for currency
92
+ if(!empty($pmpro_currencies[$pmpro_currency]) && is_array($pmpro_currencies[$pmpro_currency]))
93
+ $pmpro_currency_symbol = $pmpro_currencies[$pmpro_currency]['symbol'];
94
+ elseif(!empty($pmpro_currencies[$pmpro_currency]) && strpos($pmpro_currencies[$pmpro_currency], "(") !== false)
95
+ $pmpro_currency_symbol = pmpro_getMatches("/\((.*)\)/", $pmpro_currencies[$pmpro_currency], true);
96
+ else
97
+ $pmpro_currency_symbol = $pmpro_currency . " "; //just use the code
98
+ }
99
+ add_action("init", "pmpro_init");
100
+
101
+ //this code runs after $post is set, but before template output
102
+ function pmpro_wp()
103
+ {
104
+ if(!is_admin())
105
+ {
106
+ global $post, $pmpro_pages, $pmpro_page_name, $pmpro_page_id, $pmpro_body_classes;
107
+
108
+ //no pages yet?
109
+ if(empty($pmpro_pages))
110
+ return;
111
+
112
+ //run the appropriate preheader function
113
+ foreach($pmpro_pages as $pmpro_page_name => $pmpro_page_id)
114
+ {
115
+ if(!empty($post->post_content) && strpos($post->post_content, "[pmpro_" . $pmpro_page_name . "]") !== false)
116
+ {
117
+ //preheader
118
+ require_once(PMPRO_DIR . "/preheaders/" . $pmpro_page_name . ".php");
119
+
120
+ //add class to body
121
+ $pmpro_body_classes[] = "pmpro-" . str_replace("_", "-", $pmpro_page_name);
122
+
123
+ //shortcode
124
+ function pmpro_pages_shortcode($atts, $content=null, $code="")
125
+ {
126
+ global $pmpro_page_name;
127
+ ob_start();
128
+ if(file_exists(get_stylesheet_directory() . "/paid-memberships-pro/pages/" . $pmpro_page_name . ".php"))
129
+ include(get_stylesheet_directory() . "/paid-memberships-pro/pages/" . $pmpro_page_name . ".php");
130
+ else
131
+ include(PMPRO_DIR . "/pages/" . $pmpro_page_name . ".php");
132
+
133
+ $temp_content = ob_get_contents();
134
+ ob_end_clean();
135
+ return apply_filters("pmpro_pages_shortcode_" . $pmpro_page_name, $temp_content);
136
+ }
137
+ add_shortcode("pmpro_" . $pmpro_page_name, "pmpro_pages_shortcode");
138
+ break; //only the first page found gets a shortcode replacement
139
+ }
140
+ }
141
+ }
142
+ }
143
+ add_action("wp", "pmpro_wp", 1);
144
+
145
+ /*
146
+ Add PMPro page names to the BODY class.
147
+ */
148
+ function pmpro_body_class($classes)
149
+ {
150
+ global $pmpro_body_classes;
151
+
152
+ if(is_array($pmpro_body_classes))
153
+ $classes = array_merge($pmpro_body_classes, $classes);
154
+
155
+ return $classes;
156
+ }
157
+ add_filter("body_class", "pmpro_body_class");
158
+
159
+ //add membership level to current user object
160
+ function pmpro_set_current_user()
161
+ {
162
+ //this code runs at the beginning of the plugin
163
+ global $current_user, $wpdb;
164
+ get_currentuserinfo();
165
+ $id = intval($current_user->ID);
166
+ if($id)
167
+ {
168
+ $current_user->membership_level = pmpro_getMembershipLevelForUser($current_user->ID);
169
+ if(!empty($current_user->membership_level))
170
+ {
171
+ $current_user->membership_level->categories = pmpro_getMembershipCategories($current_user->membership_level->ID);
172
+ }
173
+ $current_user->membership_levels = pmpro_getMembershipLevelsForUser($current_user->ID);
174
+ }
175
+
176
+ //hiding ads?
177
+ $hideads = pmpro_getOption("hideads");
178
+ $hideadslevels = pmpro_getOption("hideadslevels");
179
+ if(!is_array($hideadslevels))
180
+ $hideadslevels = explode(",", $hideadslevels);
181
+ if($hideads == 1 && pmpro_hasMembershipLevel() || $hideads == 2 && pmpro_hasMembershipLevel($hideadslevels))
182
+ {
183
+ //disable ads in ezAdsense
184
+ if(class_exists("ezAdSense"))
185
+ {
186
+ global $ezCount, $urCount;
187
+ $ezCount = 100;
188
+ $urCount = 100;
189
+ }
190
+
191
+ //disable ads in Easy Adsense (newer versions)
192
+ if(class_exists("EzAdSense"))
193
+ {
194
+ global $ezAdSense;
195
+ $ezAdSense->ezCount = 100;
196
+ $ezAdSense->urCount = 100;
197
+ }
198
+
199
+ //set a global variable to hide ads
200
+ global $pmpro_display_ads;
201
+ $pmpro_display_ads = false;
202
+ }
203
+ else
204
+ {
205
+ global $pmpro_display_ads;
206
+ $pmpro_display_ads = true;
207
+ }
208
+
209
+ do_action("pmpro_after_set_current_user");
210
+ }
211
+ add_action('set_current_user', 'pmpro_set_current_user');
212
+ add_action('init', 'pmpro_set_current_user');
213
+
214
+ /*
215
+ * Add Membership Level to Users page in WordPress dashboard.
216
+ */
217
+ function pmpro_manage_users_columns($columns) {
218
+ $columns['pmpro_membership_level'] = __('Membership Level', 'pmpro');
219
+ return $columns;
220
+ }
221
+
222
+ function pmpro_manage_users_custom_column($column_data, $column_name, $user_id) {
223
+
224
+ if($column_name == 'pmpro_membership_level') {
225
+ $levels = pmpro_getMembershipLevelsForUser($user_id);
226
+ $level_names = array();
227
+ if(!empty($levels)) {
228
+ foreach($levels as $key => $level)
229
+ $level_names[] = $level->name;
230
+ $column_data = implode(',', $level_names);
231
+ }
232
+ else
233
+ $column_data = __('None', 'pmpro');
234
+ }
235
+ return $column_data;
236
+ }
237
+
238
+ add_filter('manage_users_columns', 'pmpro_manage_users_columns');
239
+ add_filter('manage_users_custom_column', 'pmpro_manage_users_custom_column', 10, 3);
240
+
includes/lib/Braintree/Braintree.php ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree base class and initialization
4
+ *
5
+ * PHP version 5
6
+ *
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+
11
+ set_include_path(get_include_path() . PATH_SEPARATOR . realpath(dirname(__FILE__)));
12
+
13
+ /**
14
+ * Braintree PHP Library
15
+ *
16
+ * Provides methods to child classes. This class cannot be instantiated.
17
+ *
18
+ * @copyright 2010 Braintree Payment Solutions
19
+ */
20
+ abstract class Braintree
21
+ {
22
+ /**
23
+ * @ignore
24
+ * don't permit an explicit call of the constructor!
25
+ * (like $t = new Braintree_Transaction())
26
+ */
27
+ protected function __construct()
28
+ {
29
+ }
30
+ /**
31
+ * @ignore
32
+ * don't permit cloning the instances (like $x = clone $v)
33
+ */
34
+ protected function __clone()
35
+ {
36
+ }
37
+
38
+ /**
39
+ * returns private/nonexistent instance properties
40
+ * @ignore
41
+ * @access public
42
+ * @param string $name property name
43
+ * @return mixed contents of instance properties
44
+ */
45
+ public function __get($name)
46
+ {
47
+ if (array_key_exists($name, $this->_attributes)) {
48
+ return $this->_attributes[$name];
49
+ }
50
+ else {
51
+ trigger_error('Undefined property on ' . get_class($this) . ': ' . $name, E_USER_NOTICE);
52
+ return null;
53
+ }
54
+ }
55
+
56
+ /**
57
+ * used by isset() and empty()
58
+ * @access public
59
+ * @param string $name property name
60
+ * @return boolean
61
+ */
62
+ public function __isset($name)
63
+ {
64
+ return array_key_exists($name, $this->_attributes);
65
+ }
66
+
67
+ public function _set($key, $value)
68
+ {
69
+ $this->_attributes[$key] = $value;
70
+ }
71
+
72
+ /**
73
+ *
74
+ * @param string $className
75
+ * @param object $resultObj
76
+ * @return object returns the passed object if successful
77
+ * @throws Braintree_Exception_ValidationsFailed
78
+ */
79
+ public static function returnObjectOrThrowException($className, $resultObj)
80
+ {
81
+ $resultObjName = Braintree_Util::cleanClassName($className);
82
+ if ($resultObj->success) {
83
+ return $resultObj->$resultObjName;
84
+ } else {
85
+ throw new Braintree_Exception_ValidationsFailed();
86
+ }
87
+ }
88
+ }
89
+ require_once('Braintree/Modification.php');
90
+ require_once('Braintree/Instance.php');
91
+
92
+ require_once('Braintree/Address.php');
93
+ require_once('Braintree/AddOn.php');
94
+ require_once('Braintree/Collection.php');
95
+ require_once('Braintree/Configuration.php');
96
+ require_once('Braintree/CreditCard.php');
97
+ require_once('Braintree/Customer.php');
98
+ require_once('Braintree/CustomerSearch.php');
99
+ require_once('Braintree/Descriptor.php');
100
+ require_once('Braintree/Digest.php');
101
+ require_once('Braintree/Discount.php');
102
+ require_once('Braintree/IsNode.php');
103
+ require_once('Braintree/EqualityNode.php');
104
+ require_once('Braintree/Exception.php');
105
+ require_once('Braintree/Http.php');
106
+ require_once('Braintree/KeyValueNode.php');
107
+ require_once('Braintree/MultipleValueNode.php');
108
+ require_once('Braintree/MultipleValueOrTextNode.php');
109
+ require_once('Braintree/PartialMatchNode.php');
110
+ require_once('Braintree/Plan.php');
111
+ require_once('Braintree/RangeNode.php');
112
+ require_once('Braintree/ResourceCollection.php');
113
+ require_once('Braintree/SettlementBatchSummary.php');
114
+ require_once('Braintree/Subscription.php');
115
+ require_once('Braintree/SubscriptionSearch.php');
116
+ require_once('Braintree/SubscriptionStatus.php');
117
+ require_once('Braintree/TextNode.php');
118
+ require_once('Braintree/Transaction.php');
119
+ require_once('Braintree/TransactionSearch.php');
120
+ require_once('Braintree/TransparentRedirect.php');
121
+ require_once('Braintree/Util.php');
122
+ require_once('Braintree/Version.php');
123
+ require_once('Braintree/Xml.php');
124
+ require_once('Braintree/Error/Codes.php');
125
+ require_once('Braintree/Error/ErrorCollection.php');
126
+ require_once('Braintree/Error/Validation.php');
127
+ require_once('Braintree/Error/ValidationErrorCollection.php');
128
+ require_once('Braintree/Exception/Authentication.php');
129
+ require_once('Braintree/Exception/Authorization.php');
130
+ require_once('Braintree/Exception/Configuration.php');
131
+ require_once('Braintree/Exception/DownForMaintenance.php');
132
+ require_once('Braintree/Exception/ForgedQueryString.php');
133
+ require_once('Braintree/Exception/InvalidSignature.php');
134
+ require_once('Braintree/Exception/NotFound.php');
135
+ require_once('Braintree/Exception/ServerError.php');
136
+ require_once('Braintree/Exception/SSLCertificate.php');
137
+ require_once('Braintree/Exception/SSLCaFileNotFound.php');
138
+ require_once('Braintree/Exception/Unexpected.php');
139
+ require_once('Braintree/Exception/UpgradeRequired.php');
140
+ require_once('Braintree/Exception/ValidationsFailed.php');
141
+ require_once('Braintree/Result/CreditCardVerification.php');
142
+ require_once('Braintree/Result/Error.php');
143
+ require_once('Braintree/Result/Successful.php');
144
+ require_once('Braintree/Test/CreditCardNumbers.php');
145
+ require_once('Braintree/Test/TransactionAmounts.php');
146
+ require_once('Braintree/Transaction/AddressDetails.php');
147
+ require_once('Braintree/Transaction/CreditCardDetails.php');
148
+ require_once('Braintree/Transaction/CustomerDetails.php');
149
+ require_once('Braintree/Transaction/StatusDetails.php');
150
+ require_once('Braintree/Transaction/SubscriptionDetails.php');
151
+ require_once('Braintree/WebhookNotification.php');
152
+ require_once('Braintree/WebhookTesting.php');
153
+ require_once('Braintree/Xml/Generator.php');
154
+ require_once('Braintree/Xml/Parser.php');
155
+ require_once('Braintree/CreditCardVerification.php');
156
+ require_once('Braintree/CreditCardVerificationSearch.php');
157
+
158
+ if (version_compare(PHP_VERSION, '5.2.1', '<')) {
159
+ throw new Braintree_Exception('PHP version >= 5.2.1 required');
160
+ }
161
+
162
+
163
+ function requireDependencies() {
164
+ $requiredExtensions = array('xmlwriter', 'SimpleXML', 'openssl', 'dom', 'hash', 'curl');
165
+ foreach ($requiredExtensions AS $ext) {
166
+ if (!extension_loaded($ext)) {
167
+ throw new Braintree_Exception('The Braintree library requires the ' . $ext . ' extension.');
168
+ }
169
+ }
170
+ }
171
+
172
+ requireDependencies();
includes/lib/Braintree/Braintree/AddOn.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_AddOn extends Braintree_Modification
3
+ {
4
+ public static function all()
5
+ {
6
+ $response = Braintree_Http::get('/add_ons');
7
+
8
+ $addOns = array("addOn" => $response['addOns']);
9
+
10
+ return Braintree_Util::extractAttributeAsArray(
11
+ $addOns,
12
+ 'addOn'
13
+ );
14
+ }
15
+ }
includes/lib/Braintree/Braintree/Address.php ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Address module
4
+ *
5
+ * PHP Version 5
6
+ *
7
+ * @package Braintree
8
+ * @copyright 2010 Braintree Payment Solutions
9
+ */
10
+ /**
11
+ * Creates and manages Braintree Addresses
12
+ *
13
+ * An Address belongs to a Customer. It can be associated to a
14
+ * CreditCard as the billing address. It can also be used
15
+ * as the shipping address when creating a Transaction.
16
+ *
17
+ * @package Braintree
18
+ * @copyright 2010 Braintree Payment Solutions
19
+ *
20
+ * @property-read string $company
21
+ * @property-read string $countryName
22
+ * @property-read string $createdAt
23
+ * @property-read string $customerId
24
+ * @property-read string $extendedAddress
25
+ * @property-read string $firstName
26
+ * @property-read string $id
27
+ * @property-read string $lastName
28
+ * @property-read string $locality
29
+ * @property-read string $postalCode
30
+ * @property-read string $region
31
+ * @property-read string $streetAddress
32
+ * @property-read string $updatedAt
33
+ */
34
+ class Braintree_Address extends Braintree
35
+ {
36
+
37
+ /* public class methods */
38
+ /**
39
+ *
40
+ * @access public
41
+ * @param array $attribs
42
+ * @return object Result, either Successful or Error
43
+ */
44
+ public static function create($attribs)
45
+ {
46
+ Braintree_Util::verifyKeys(self::createSignature(), $attribs);
47
+ $customerId = isset($attribs['customerId']) ?
48
+ $attribs['customerId'] :
49
+ null;
50
+
51
+ self::_validateCustomerId($customerId);
52
+ unset($attribs['customerId']);
53
+ return self::_doCreate(
54
+ '/customers/' . $customerId . '/addresses',
55
+ array('address' => $attribs)
56
+ );
57
+ }
58
+
59
+ /**
60
+ * attempts the create operation assuming all data will validate
61
+ * returns a Braintree_Address object instead of a Result
62
+ *
63
+ * @access public
64
+ * @param array $attribs
65
+ * @return object
66
+ * @throws Braintree_Exception_ValidationError
67
+ */
68
+ public static function createNoValidate($attribs)
69
+ {
70
+ $result = self::create($attribs);
71
+ return self::returnObjectOrThrowException(__CLASS__, $result);
72
+
73
+ }
74
+
75
+ /**
76
+ * delete an address by id
77
+ *
78
+ * @param mixed $customerOrId
79
+ * @param string $addressId
80
+ */
81
+ public static function delete($customerOrId = null, $addressId = null)
82
+ {
83
+ self::_validateId($addressId);
84
+ $customerId = self::_determineCustomerId($customerOrId);
85
+ Braintree_Http::delete(
86
+ '/customers/' . $customerId . '/addresses/' . $addressId
87
+ );
88
+ return new Braintree_Result_Successful();
89
+ }
90
+
91
+ /**
92
+ * find an address by id
93
+ *
94
+ * Finds the address with the given <b>addressId</b> that is associated
95
+ * to the given <b>customerOrId</b>.
96
+ * If the address cannot be found, a NotFound exception will be thrown.
97
+ *
98
+ *
99
+ * @access public
100
+ * @param mixed $customerOrId
101
+ * @param string $addressId
102
+ * @return object Braintree_Address
103
+ * @throws Braintree_Exception_NotFound
104
+ */
105
+ public static function find($customerOrId, $addressId)
106
+ {
107
+
108
+ $customerId = self::_determineCustomerId($customerOrId);
109
+ self::_validateId($addressId);
110
+
111
+ try {
112
+ $response = Braintree_Http::get(
113
+ '/customers/' . $customerId . '/addresses/' . $addressId
114
+ );
115
+ return self::factory($response['address']);
116
+ } catch (Braintree_Exception_NotFound $e) {
117
+ throw new Braintree_Exception_NotFound(
118
+ 'address for customer ' . $customerId .
119
+ ' with id ' . $addressId . ' not found.'
120
+ );
121
+ }
122
+
123
+ }
124
+
125
+ /**
126
+ * returns false if comparing object is not a Braintree_Address,
127
+ * or is a Braintree_Address with a different id
128
+ *
129
+ * @param object $other address to compare against
130
+ * @return boolean
131
+ */
132
+ public function isEqual($other)
133
+ {
134
+ return !($other instanceof Braintree_Address) ?
135
+ false :
136
+ ($this->id === $other->id && $this->customerId === $other->customerId);
137
+ }
138
+
139
+ /**
140
+ * updates the address record
141
+ *
142
+ * if calling this method in static context,
143
+ * customerOrId is the 2nd attribute, addressId 3rd.
144
+ * customerOrId & addressId are not sent in object context.
145
+ *
146
+ *
147
+ * @access public
148
+ * @param array $attributes
149
+ * @param mixed $customerOrId (only used in static call)
150
+ * @param string $addressId (only used in static call)
151
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
152
+ */
153
+ public static function update($customerOrId, $addressId, $attributes)
154
+ {
155
+ self::_validateId($addressId);
156
+ $customerId = self::_determineCustomerId($customerOrId);
157
+ Braintree_Util::verifyKeys(self::updateSignature(), $attributes);
158
+
159
+ $response = Braintree_Http::put(
160
+ '/customers/' . $customerId . '/addresses/' . $addressId,
161
+ array('address' => $attributes)
162
+ );
163
+
164
+ return self::_verifyGatewayResponse($response);
165
+
166
+ }
167
+
168
+ /**
169
+ * update an address record, assuming validations will pass
170
+ *
171
+ * if calling this method in static context,
172
+ * customerOrId is the 2nd attribute, addressId 3rd.
173
+ * customerOrId & addressId are not sent in object context.
174
+ *
175
+ * @access public
176
+ * @param array $transactionAttribs
177
+ * @param string $customerId
178
+ * @return object Braintree_Transaction
179
+ * @throws Braintree_Exception_ValidationsFailed
180
+ * @see Braintree_Address::update()
181
+ */
182
+ public static function updateNoValidate($customerOrId, $addressId, $attributes)
183
+ {
184
+ $result = self::update($customerOrId, $addressId, $attributes);
185
+ return self::returnObjectOrThrowException(__CLASS__, $result);
186
+ }
187
+
188
+ /**
189
+ * creates a full array signature of a valid create request
190
+ * @return array gateway create request format
191
+ */
192
+ public static function createSignature()
193
+ {
194
+ return array(
195
+ 'company', 'countryCodeAlpha2', 'countryCodeAlpha3', 'countryCodeNumeric',
196
+ 'countryName', 'customerId', 'extendedAddress', 'firstName',
197
+ 'lastName', 'locality', 'postalCode', 'region', 'streetAddress'
198
+ );
199
+ }
200
+
201
+ /**
202
+ * creates a full array signature of a valid update request
203
+ * @return array gateway update request format
204
+ */
205
+ public static function updateSignature()
206
+ {
207
+ // TODO: remove customerId from update signature
208
+ return self::createSignature();
209
+
210
+ }
211
+
212
+ /**
213
+ * create a printable representation of the object as:
214
+ * ClassName[property=value, property=value]
215
+ * @ignore
216
+ * @return var
217
+ */
218
+ public function __toString()
219
+ {
220
+ return __CLASS__ . '[' .
221
+ Braintree_Util::attributesToString($this->_attributes) .']';
222
+ }
223
+
224
+ /**
225
+ * sets instance properties from an array of values
226
+ *
227
+ * @ignore
228
+ * @access protected
229
+ * @param array $addressAttribs array of address data
230
+ * @return none
231
+ */
232
+ protected function _initialize($addressAttribs)
233
+ {
234
+ // set the attributes
235
+ $this->_attributes = $addressAttribs;
236
+ }
237
+
238
+ /**
239
+ * verifies that a valid address id is being used
240
+ * @ignore
241
+ * @param string $id address id
242
+ * @throws InvalidArgumentException
243
+ */
244
+ private static function _validateId($id = null)
245
+ {
246
+ if (empty($id) || trim($id) == "") {
247
+ throw new InvalidArgumentException(
248
+ 'expected address id to be set'
249
+ );
250
+ }
251
+ if (!preg_match('/^[0-9A-Za-z_-]+$/', $id)) {
252
+ throw new InvalidArgumentException(
253
+ $id . ' is an invalid address id.'
254
+ );
255
+ }
256
+ }
257
+
258
+ /**
259
+ * verifies that a valid customer id is being used
260
+ * @ignore
261
+ * @param string $id customer id
262
+ * @throws InvalidArgumentException
263
+ */
264
+ private static function _validateCustomerId($id = null)
265
+ {
266
+ if (empty($id) || trim($id) == "") {
267
+ throw new InvalidArgumentException(
268
+ 'expected customer id to be set'
269
+ );
270
+ }
271
+ if (!preg_match('/^[0-9A-Za-z_-]+$/', $id)) {
272
+ throw new InvalidArgumentException(
273
+ $id . ' is an invalid customer id.'
274
+ );
275
+ }
276
+
277
+ }
278
+
279
+ /**
280
+ * determines if a string id or Customer object was passed
281
+ * @ignore
282
+ * @param mixed $customerOrId
283
+ * @return string customerId
284
+ */
285
+ private static function _determineCustomerId($customerOrId)
286
+ {
287
+ $customerId = ($customerOrId instanceof Braintree_Customer) ? $customerOrId->id : $customerOrId;
288
+ self::_validateCustomerId($customerId);
289
+ return $customerId;
290
+
291
+ }
292
+
293
+ /* private class methods */
294
+ /**
295
+ * sends the create request to the gateway
296
+ * @ignore
297
+ * @param string $url
298
+ * @param array $params
299
+ * @return mixed
300
+ */
301
+ private static function _doCreate($url, $params)
302
+ {
303
+ $response = Braintree_Http::post($url, $params);
304
+
305
+ return self::_verifyGatewayResponse($response);
306
+
307
+ }
308
+
309
+ /**
310
+ * generic method for validating incoming gateway responses
311
+ *
312
+ * creates a new Braintree_Address object and encapsulates
313
+ * it inside a Braintree_Result_Successful object, or
314
+ * encapsulates a Braintree_Errors object inside a Result_Error
315
+ * alternatively, throws an Unexpected exception if the response is invalid.
316
+ *
317
+ * @ignore
318
+ * @param array $response gateway response values
319
+ * @return object Result_Successful or Result_Error
320
+ * @throws Braintree_Exception_Unexpected
321
+ */
322
+ private static function _verifyGatewayResponse($response)
323
+ {
324
+ if (isset($response['address'])) {
325
+ // return a populated instance of Braintree_Address
326
+ return new Braintree_Result_Successful(
327
+ self::factory($response['address'])
328
+ );
329
+ } else if (isset($response['apiErrorResponse'])) {
330
+ return new Braintree_Result_Error($response['apiErrorResponse']);
331
+ } else {
332
+ throw new Braintree_Exception_Unexpected(
333
+ "Expected address or apiErrorResponse"
334
+ );
335
+ }
336
+
337
+ }
338
+
339
+ /**
340
+ * factory method: returns an instance of Braintree_Address
341
+ * to the requesting method, with populated properties
342
+ * @ignore
343
+ * @return object instance of Braintree_Address
344
+ */
345
+ public static function factory($attributes)
346
+ {
347
+ $instance = new self();
348
+ $instance->_initialize($attributes);
349
+ return $instance;
350
+
351
+ }
352
+ }
includes/lib/Braintree/Braintree/Collection.php ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Generic collection
4
+ *
5
+ * PHP Version 5
6
+ *
7
+ * @package Braintree
8
+ * @subpackage Utility
9
+ * @copyright 2010 Braintree Payment Solutions
10
+ */
11
+
12
+ /**
13
+ * Generic Collection class
14
+ *
15
+ * Based on Generic Collection class from:
16
+ * {@link http://codeutopia.net/code/library/CU/Collection.php}
17
+ *
18
+ * @package Braintree
19
+ * @subpackage Utility
20
+ */
21
+ class Braintree_Collection implements Countable, IteratorAggregate, ArrayAccess
22
+ {
23
+ /**
24
+ *
25
+ * @var array $_collection collection storage
26
+ */
27
+ protected $_collection = array();
28
+
29
+ /**
30
+ * Add a value into the collection
31
+ * @param string $value
32
+ */
33
+ public function add($value)
34
+ {
35
+ $this->_collection[] = $value;
36
+ }
37
+
38
+ /**
39
+ * Set index's value
40
+ * @param integer $index
41
+ * @param mixed $value
42
+ * @throws OutOfRangeException
43
+ */
44
+ public function set($index, $value)
45
+ {
46
+ if($index >= $this->count())
47
+ throw new OutOfRangeException('Index out of range');
48
+
49
+ $this->_collection[$index] = $value;
50
+ }
51
+
52
+ /**
53
+ * Remove a value from the collection
54
+ * @param integer $index index to remove
55
+ * @throws OutOfRangeException if index is out of range
56
+ */
57
+ public function remove($index)
58
+ {
59
+ if($index >= $this->count())
60
+ throw new OutOfRangeException('Index out of range');
61
+
62
+ array_splice($this->_collection, $index, 1);
63
+ }
64
+
65
+ /**
66
+ * Return value at index
67
+ * @param integer $index
68
+ * @return mixed
69
+ * @throws OutOfRangeException
70
+ */
71
+ public function get($index)
72
+ {
73
+ if($index >= $this->count())
74
+ throw new OutOfRangeException('Index out of range');
75
+
76
+ return $this->_collection[$index];
77
+ }
78
+
79
+ /**
80
+ * Determine if index exists
81
+ * @param integer $index
82
+ * @return boolean
83
+ */
84
+ public function exists($index)
85
+ {
86
+ if($index >= $this->count())
87
+ return false;
88
+
89
+ return true;
90
+ }
91
+ /**
92
+ * Return count of items in collection
93
+ * Implements countable
94
+ * @return integer
95
+ */
96
+ public function count()
97
+ {
98
+ return count($this->_collection);
99
+ }
100
+
101
+
102
+ /**
103
+ * Return an iterator
104
+ * Implements IteratorAggregate
105
+ * @return ArrayIterator
106
+ */
107
+ public function getIterator()
108
+ {
109
+ return new ArrayIterator($this->_collection);
110
+ }
111
+
112
+ /**
113
+ * Set offset to value
114
+ * Implements ArrayAccess
115
+ * @see set
116
+ * @param integer $offset
117
+ * @param mixed $value
118
+ */
119
+ public function offsetSet($offset, $value)
120
+ {
121
+ $this->set($offset, $value);
122
+ }
123
+
124
+ /**
125
+ * Unset offset
126
+ * Implements ArrayAccess
127
+ * @see remove
128
+ * @param integer $offset
129
+ */
130
+ public function offsetUnset($offset)
131
+ {
132
+ $this->remove($offset);
133
+ }
134
+
135
+ /**
136
+ * get an offset's value
137
+ * Implements ArrayAccess
138
+ * @see get
139
+ * @param integer $offset
140
+ * @return mixed
141
+ */
142
+ public function offsetGet($offset)
143
+ {
144
+ return $this->get($offset);
145
+ }
146
+
147
+ /**
148
+ * Determine if offset exists
149
+ * Implements ArrayAccess
150
+ * @see exists
151
+ * @param integer $offset
152
+ * @return boolean
153
+ */
154
+ public function offsetExists($offset)
155
+ {
156
+ return $this->exists($offset);
157
+ }
158
+
159
+ }
includes/lib/Braintree/Braintree/Configuration.php ADDED
@@ -0,0 +1,346 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * Configuration registry
5
+ *
6
+ * @package Braintree
7
+ * @subpackage Utility
8
+ * @copyright 2010 Braintree Payment Solutions
9
+ */
10
+
11
+ /**
12
+ * acts as a registry for config data.
13
+ *
14
+ *
15
+ * @package Braintree
16
+ * @subpackage Utility
17
+ *
18
+ * */
19
+
20
+ class Braintree_Configuration extends Braintree
21
+ {
22
+ /**
23
+ * Braintree API version to use
24
+ * @access public
25
+ */
26
+ const API_VERSION = 3;
27
+
28
+ /**
29
+ * @var array array of config properties
30
+ * @access protected
31
+ * @static
32
+ */
33
+ private static $_cache = array(
34
+ 'environment' => '',
35
+ 'merchantId' => '',
36
+ 'publicKey' => '',
37
+ 'privateKey' => '',
38
+ );
39
+ /**
40
+ *
41
+ * @access protected
42
+ * @static
43
+ * @var array valid environments, used for validation
44
+ */
45
+ private static $_validEnvironments = array(
46
+ 'development',
47
+ 'sandbox',
48
+ 'production',
49
+ 'qa',
50
+ );
51
+
52
+ /**
53
+ * resets configuration to default
54
+ * @access public
55
+ * @static
56
+ */
57
+ public static function reset()
58
+ {
59
+ self::$_cache = array (
60
+ 'environment' => '',
61
+ 'merchantId' => '',
62
+ 'publicKey' => '',
63
+ 'privateKey' => '',
64
+ );
65
+ }
66
+
67
+ /**
68
+ * performs sanity checks when config settings are being set
69
+ *
70
+ * @ignore
71
+ * @access protected
72
+ * @param string $key name of config setting
73
+ * @param string $value value to set
74
+ * @throws InvalidArgumentException
75
+ * @throws Braintree_Exception_Configuration
76
+ * @static
77
+ * @return boolean
78
+ */
79
+ private static function validate($key=null, $value=null)
80
+ {
81
+ if (empty($key) && empty($value)) {
82
+ throw new InvalidArgumentException('nothing to validate');
83
+ }
84
+
85
+ if ($key === 'environment' &&
86
+ !in_array($value, self::$_validEnvironments) ) {
87
+ throw new Braintree_Exception_Configuration('"' .
88
+ $value . '" is not a valid environment.');
89
+ }
90
+
91
+ if (!isset(self::$_cache[$key])) {
92
+ throw new Braintree_Exception_Configuration($key .
93
+ ' is not a valid configuration setting.');
94
+ }
95
+
96
+ if (empty($value)) {
97
+ throw new InvalidArgumentException($key . ' cannot be empty.');
98
+ }
99
+
100
+ return true;
101
+ }
102
+
103
+ private static function set($key, $value)
104
+ {
105
+ // this method will raise an exception on invalid data
106
+ self::validate($key, $value);
107
+ // set the value in the cache
108
+ self::$_cache[$key] = $value;
109
+
110
+ }
111
+
112
+ private static function get($key)
113
+ {
114
+ // throw an exception if the value hasn't been set
115
+ if (isset(self::$_cache[$key]) &&
116
+ (empty(self::$_cache[$key]))) {
117
+ throw new Braintree_Exception_Configuration(
118
+ $key.' needs to be set'
119
+ );
120
+ }
121
+
122
+ if (array_key_exists($key, self::$_cache)) {
123
+ return self::$_cache[$key];
124
+ }
125
+
126
+ // return null by default to prevent __set from overloading
127
+ return null;
128
+ }
129
+
130
+
131
+ private static function setOrGet($name, $value = null)
132
+ {
133
+ if (!empty($value) && is_array($value)) {
134
+ $value = $value[0];
135
+ }
136
+ if (!empty($value)) {
137
+ self::set($name, $value);
138
+ } else {
139
+ return self::get($name);
140
+ }
141
+ return true;
142
+ }
143
+ /**#@+
144
+ * sets or returns the property after validation
145
+ * @access public
146
+ * @static
147
+ * @param string $value pass a string to set, empty to get
148
+ * @return mixed returns true on set
149
+ */
150
+ public static function environment($value = null)
151
+ {
152
+ return self::setOrGet(__FUNCTION__, $value);
153
+ }
154
+
155
+ public static function merchantId($value = null)
156
+ {
157
+ return self::setOrGet(__FUNCTION__, $value);
158
+ }
159
+
160
+ public static function publicKey($value = null)
161
+ {
162
+ return self::setOrGet(__FUNCTION__, $value);
163
+ }
164
+
165
+ public static function privateKey($value = null)
166
+ {
167
+ return self::setOrGet(__FUNCTION__, $value);
168
+ }
169
+ /**#@-*/
170
+
171
+ /**
172
+ * returns the full merchant URL based on config values
173
+ *
174
+ * @access public
175
+ * @static
176
+ * @param none
177
+ * @return string merchant URL
178
+ */
179
+ public static function merchantUrl()
180
+ {
181
+ return self::baseUrl() .
182
+ self::merchantPath();
183
+ }
184
+
185
+ /**
186
+ * returns the base braintree gateway URL based on config values
187
+ *
188
+ * @access public
189
+ * @static
190
+ * @param none
191
+ * @return string braintree gateway URL
192
+ */
193
+ public static function baseUrl()
194
+ {
195
+ return self::protocol() . '://' .
196
+ self::serverName() . ':' .
197
+ self::portNumber();
198
+ }
199
+
200
+ /**
201
+ * sets the merchant path based on merchant ID
202
+ *
203
+ * @access protected
204
+ * @static
205
+ * @param none
206
+ * @return string merchant path uri
207
+ */
208
+ public static function merchantPath()
209
+ {
210
+ return '/merchants/'.self::merchantId();
211
+ }
212
+
213
+ /**
214
+ * sets the physical path for the location of the CA certs
215
+ *
216
+ * @access public
217
+ * @static
218
+ * @param none
219
+ * @return string filepath
220
+ */
221
+ public static function caFile($sslPath = NULL)
222
+ {
223
+ $sslPath = $sslPath ? $sslPath : DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR .
224
+ 'ssl' . DIRECTORY_SEPARATOR;
225
+
226
+ switch(self::environment()) {
227
+ case 'production':
228
+ $caPath = realpath(
229
+ dirname(__FILE__) .
230
+ $sslPath . 'www_braintreegateway_com.ca.crt'
231
+ );
232
+ break;
233
+ case 'qa':
234
+ case 'sandbox':
235
+ default:
236
+ $caPath = realpath(
237
+ dirname(__FILE__) .
238
+ $sslPath . 'sandbox_braintreegateway_com.ca.crt'
239
+ );
240
+ break;
241
+ }
242
+
243
+ if (!file_exists($caPath))
244
+ {
245
+ throw new Braintree_Exception_SSLCaFileNotFound();
246
+ }
247
+
248
+ return $caPath;
249
+ }
250
+
251
+ /**
252
+ * returns the port number depending on environment
253
+ *
254
+ * @access public
255
+ * @static
256
+ * @param none
257
+ * @return int portnumber
258
+ */
259
+ public static function portNumber()
260
+ {
261
+ if (self::sslOn()) {
262
+ return 443;
263
+ }
264
+ return getenv("GATEWAY_PORT") ? getenv("GATEWAY_PORT") : 3000;
265
+ }
266
+
267
+ /**
268
+ * returns http protocol depending on environment
269
+ *
270
+ * @access public
271
+ * @static
272
+ * @param none
273
+ * @return string http || https
274
+ */
275
+ public static function protocol()
276
+ {
277
+ return self::sslOn() ? 'https' : 'http';
278
+ }
279
+
280
+ /**
281
+ * returns gateway server name depending on environment
282
+ *
283
+ * @access public
284
+ * @static
285
+ * @param none
286
+ * @return string server domain name
287
+ */
288
+ public static function serverName()
289
+ {
290
+ switch(self::environment()) {
291
+ case 'production':
292
+ $serverName = 'www.braintreegateway.com';
293
+ break;
294
+ case 'qa':
295
+ $serverName = 'qa.braintreegateway.com';
296
+ break;
297
+ case 'sandbox':
298
+ $serverName = 'sandbox.braintreegateway.com';
299
+ break;
300
+ case 'development':
301
+ default:
302
+ $serverName = 'localhost';
303
+ break;
304
+ }
305
+
306
+ return $serverName;
307
+ }
308
+
309
+ /**
310
+ * returns boolean indicating SSL is on or off for this session,
311
+ * depending on environment
312
+ *
313
+ * @access public
314
+ * @static
315
+ * @param none
316
+ * @return boolean
317
+ */
318
+ public static function sslOn()
319
+ {
320
+ switch(self::environment()) {
321
+ case 'development':
322
+ $ssl = false;
323
+ break;
324
+ case 'production':
325
+ case 'qa':
326
+ case 'sandbox':
327
+ default:
328
+ $ssl = true;
329
+ break;
330
+ }
331
+
332
+ return $ssl;
333
+ }
334
+
335
+ /**
336
+ * log message to default logger
337
+ *
338
+ * @param string $message
339
+ *
340
+ */
341
+ public static function logMessage($message)
342
+ {
343
+ error_log('[Braintree] ' . $message);
344
+ }
345
+
346
+ }
includes/lib/Braintree/Braintree/CreditCard.php ADDED
@@ -0,0 +1,591 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree CreditCard module
4
+ *
5
+ * @package Braintree
6
+ * @category Resources
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Creates and manages Braintree CreditCards
12
+ *
13
+ * <b>== More information ==</b>
14
+ *
15
+ * For more detailed information on CreditCards, see {@link http://www.braintreepayments.com/gateway/credit-card-api http://www.braintreepaymentsolutions.com/gateway/credit-card-api}<br />
16
+ * For more detailed information on CreditCard verifications, see {@link http://www.braintreepayments.com/gateway/credit-card-verification-api http://www.braintreepaymentsolutions.com/gateway/credit-card-verification-api}
17
+ *
18
+ * @package Braintree
19
+ * @category Resources
20
+ * @copyright 2010 Braintree Payment Solutions
21
+ *
22
+ * @property-read string $billingAddress
23
+ * @property-read string $bin
24
+ * @property-read string $cardType
25
+ * @property-read string $cardholderName
26
+ * @property-read string $createdAt
27
+ * @property-read string $customerId
28
+ * @property-read string $expirationDate
29
+ * @property-read string $expirationMonth
30
+ * @property-read string $expirationYear
31
+ * @property-read string $last4
32
+ * @property-read string $maskedNumber
33
+ * @property-read string $token
34
+ * @property-read string $updatedAt
35
+ */
36
+ class Braintree_CreditCard extends Braintree
37
+ {
38
+ // Card Type
39
+ const AMEX = 'American Express';
40
+ const CARTE_BLANCHE = 'Carte Blanche';
41
+ const CHINA_UNION_PAY = 'China UnionPay';
42
+ const DINERS_CLUB_INTERNATIONAL = 'Diners Club';
43
+ const DISCOVER = 'Discover';
44
+ const JCB = 'JCB';
45
+ const LASER = 'Laser';
46
+ const MAESTRO = 'Maestro';
47
+ const MASTER_CARD = 'MasterCard';
48
+ const SOLO = 'Solo';
49
+ const SWITCH_TYPE = 'Switch';
50
+ const VISA = 'Visa';
51
+ const UNKNOWN = 'Unknown';
52
+
53
+ // Credit card origination location
54
+ const INTERNATIONAL = "international";
55
+ const US = "us";
56
+
57
+ const PREPAID_YES = 'Yes';
58
+ const PREPAID_NO = 'No';
59
+ const PREPAID_UNKNOWN = 'Unknown';
60
+
61
+ const PAYROLL_YES = 'Yes';
62
+ const PAYROLL_NO = 'No';
63
+ const PAYROLL_UNKNOWN = 'Unknown';
64
+
65
+ const HEALTHCARE_YES = 'Yes';
66
+ const HEALTHCARE_NO = 'No';
67
+ const HEALTHCARE_UNKNOWN = 'Unknown';
68
+
69
+ const DURBIN_REGULATED_YES = 'Yes';
70
+ const DURBIN_REGULATED_NO = 'No';
71
+ const DURBIN_REGULATED_UNKNOWN = 'Unknown';
72
+
73
+ const DEBIT_YES = 'Yes';
74
+ const DEBIT_NO = 'No';
75
+ const DEBIT_UNKNOWN = 'Unknown';
76
+
77
+ const COMMERCIAL_YES = 'Yes';
78
+ const COMMERCIAL_NO = 'No';
79
+ const COMMERCIAL_UNKNOWN = 'Unknown';
80
+
81
+ const COUNTRY_OF_ISSUANCE_UNKNOWN = "Unknown";
82
+ const ISSUING_BANK_UNKNOWN = "Unknown";
83
+
84
+ public static function create($attribs)
85
+ {
86
+ Braintree_Util::verifyKeys(self::createSignature(), $attribs);
87
+ return self::_doCreate('/payment_methods', array('credit_card' => $attribs));
88
+ }
89
+
90
+ /**
91
+ * attempts the create operation assuming all data will validate
92
+ * returns a Braintree_CreditCard object instead of a Result
93
+ *
94
+ * @access public
95
+ * @param array $attribs
96
+ * @return object
97
+ * @throws Braintree_Exception_ValidationError
98
+ */
99
+ public static function createNoValidate($attribs)
100
+ {
101
+ $result = self::create($attribs);
102
+ return self::returnObjectOrThrowException(__CLASS__, $result);
103
+ }
104
+ /**
105
+ * create a customer from a TransparentRedirect operation
106
+ *
107
+ * @access public
108
+ * @param array $attribs
109
+ * @return object
110
+ */
111
+ public static function createFromTransparentRedirect($queryString)
112
+ {
113
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::confirm", E_USER_NOTICE);
114
+ $params = Braintree_TransparentRedirect::parseAndValidateQueryString(
115
+ $queryString
116
+ );
117
+ return self::_doCreate(
118
+ '/payment_methods/all/confirm_transparent_redirect_request',
119
+ array('id' => $params['id'])
120
+ );
121
+ }
122
+
123
+ /**
124
+ *
125
+ * @access public
126
+ * @param none
127
+ * @return string
128
+ */
129
+ public static function createCreditCardUrl()
130
+ {
131
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::url", E_USER_NOTICE);
132
+ return Braintree_Configuration::merchantUrl() .
133
+ '/payment_methods/all/create_via_transparent_redirect_request';
134
+ }
135
+
136
+ /**
137
+ * returns a ResourceCollection of expired credit cards
138
+ * @return object ResourceCollection
139
+ */
140
+ public static function expired()
141
+ {
142
+ $response = Braintree_Http::post("/payment_methods/all/expired_ids");
143
+ $pager = array(
144
+ 'className' => __CLASS__,
145
+ 'classMethod' => 'fetchExpired',
146
+ 'methodArgs' => array()
147
+ );
148
+
149
+ return new Braintree_ResourceCollection($response, $pager);
150
+ }
151
+
152
+ public static function fetchExpired($ids)
153
+ {
154
+ $response = Braintree_Http::post("/payment_methods/all/expired", array('search' => array('ids' => $ids)));
155
+
156
+ return braintree_util::extractattributeasarray(
157
+ $response['paymentMethods'],
158
+ 'creditCard'
159
+ );
160
+ }
161
+ /**
162
+ * returns a ResourceCollection of credit cards expiring between start/end
163
+ *
164
+ * @return object ResourceCollection
165
+ */
166
+ public static function expiringBetween($startDate, $endDate)
167
+ {
168
+ $queryPath = '/payment_methods/all/expiring_ids?start=' . date('mY', $startDate) . '&end=' . date('mY', $endDate);
169
+ $response = Braintree_Http::post($queryPath);
170
+ $pager = array(
171
+ 'className' => __CLASS__,
172
+ 'classMethod' => 'fetchExpiring',
173
+ 'methodArgs' => array($startDate, $endDate)
174
+ );
175
+
176
+ return new Braintree_ResourceCollection($response, $pager);
177
+ }
178
+
179
+ public static function fetchExpiring($startDate, $endDate, $ids)
180
+ {
181
+ $queryPath = '/payment_methods/all/expiring?start=' . date('mY', $startDate) . '&end=' . date('mY', $endDate);
182
+ $response = Braintree_Http::post($queryPath, array('search' => array('ids' => $ids)));
183
+
184
+ return Braintree_Util::extractAttributeAsArray(
185
+ $response['paymentMethods'],
186
+ 'creditCard'
187
+ );
188
+ }
189
+
190
+ /**
191
+ * find a creditcard by token
192
+ *
193
+ * @access public
194
+ * @param string $token credit card unique id
195
+ * @return object Braintree_CreditCard
196
+ * @throws Braintree_Exception_NotFound
197
+ */
198
+ public static function find($token)
199
+ {
200
+ self::_validateId($token);
201
+ try {
202
+ $response = Braintree_Http::get('/payment_methods/'.$token);
203
+ return self::factory($response['creditCard']);
204
+ } catch (Braintree_Exception_NotFound $e) {
205
+ throw new Braintree_Exception_NotFound(
206
+ 'credit card with token ' . $token . ' not found'
207
+ );
208
+ }
209
+
210
+ }
211
+
212
+ /**
213
+ * create a credit on the card for the passed transaction
214
+ *
215
+ * @access public
216
+ * @param array $attribs
217
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
218
+ */
219
+ public static function credit($token, $transactionAttribs)
220
+ {
221
+ self::_validateId($token);
222
+ return Braintree_Transaction::credit(
223
+ array_merge(
224
+ $transactionAttribs,
225
+ array('paymentMethodToken' => $token)
226
+ )
227
+ );
228
+ }
229
+
230
+ /**
231
+ * create a credit on this card, assuming validations will pass
232
+ *
233
+ * returns a Braintree_Transaction object on success
234
+ *
235
+ * @access public
236
+ * @param array $attribs
237
+ * @return object Braintree_Transaction
238
+ * @throws Braintree_Exception_ValidationError
239
+ */
240
+ public static function creditNoValidate($token, $transactionAttribs)
241
+ {
242
+ $result = self::credit($token, $transactionAttribs);
243
+ return self::returnObjectOrThrowException('Transaction', $result);
244
+ }
245
+
246
+ /**
247
+ * create a new sale for the current card
248
+ *
249
+ * @param string $token
250
+ * @param array $transactionAttribs
251
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
252
+ * @see Braintree_Transaction::sale()
253
+ */
254
+ public static function sale($token, $transactionAttribs)
255
+ {
256
+ self::_validateId($token);
257
+ return Braintree_Transaction::sale(
258
+ array_merge(
259
+ $transactionAttribs,
260
+ array('paymentMethodToken' => $token)
261
+ )
262
+ );
263
+ }
264
+
265
+ /**
266
+ * create a new sale using this card, assuming validations will pass
267
+ *
268
+ * returns a Braintree_Transaction object on success
269
+ *
270
+ * @access public
271
+ * @param array $transactionAttribs
272
+ * @param string $token
273
+ * @return object Braintree_Transaction
274
+ * @throws Braintree_Exception_ValidationsFailed
275
+ * @see Braintree_Transaction::sale()
276
+ */
277
+ public static function saleNoValidate($token, $transactionAttribs)
278
+ {
279
+ $result = self::sale($token, $transactionAttribs);
280
+ return self::returnObjectOrThrowException('Transaction', $result);
281
+ }
282
+
283
+ /**
284
+ * updates the creditcard record
285
+ *
286
+ * if calling this method in static context, $token
287
+ * is the 2nd attribute. $token is not sent in object context.
288
+ *
289
+ * @access public
290
+ * @param array $attributes
291
+ * @param string $token (optional)
292
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
293
+ */
294
+ public static function update($token, $attributes)
295
+ {
296
+ Braintree_Util::verifyKeys(self::updateSignature(), $attributes);
297
+ self::_validateId($token);
298
+ return self::_doUpdate('put', '/payment_methods/' . $token, array('creditCard' => $attributes));
299
+ }
300
+
301
+ /**
302
+ * update a creditcard record, assuming validations will pass
303
+ *
304
+ * if calling this method in static context, $token
305
+ * is the 2nd attribute. $token is not sent in object context.
306
+ * returns a Braintree_CreditCard object on success
307
+ *
308
+ * @access public
309
+ * @param array $attributes
310
+ * @param string $token
311
+ * @return object Braintree_CreditCard
312
+ * @throws Braintree_Exception_ValidationsFailed
313
+ */
314
+ public static function updateNoValidate($token, $attributes)
315
+ {
316
+ $result = self::update($token, $attributes);
317
+ return self::returnObjectOrThrowException(__CLASS__, $result);
318
+ }
319
+ /**
320
+ *
321
+ * @access public
322
+ * @param none
323
+ * @return string
324
+ */
325
+ public static function updateCreditCardUrl()
326
+ {
327
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::url", E_USER_NOTICE);
328
+ return Braintree_Configuration::merchantUrl() .
329
+ '/payment_methods/all/update_via_transparent_redirect_request';
330
+ }
331
+
332
+ /**
333
+ * update a customer from a TransparentRedirect operation
334
+ *
335
+ * @access public
336
+ * @param array $attribs
337
+ * @return object
338
+ */
339
+ public static function updateFromTransparentRedirect($queryString)
340
+ {
341
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::confirm", E_USER_NOTICE);
342
+ $params = Braintree_TransparentRedirect::parseAndValidateQueryString(
343
+ $queryString
344
+ );
345
+ return self::_doUpdate(
346
+ 'post',
347
+ '/payment_methods/all/confirm_transparent_redirect_request',
348
+ array('id' => $params['id'])
349
+ );
350
+ }
351
+
352
+ /* instance methods */
353
+ /**
354
+ * returns false if default is null or false
355
+ *
356
+ * @return boolean
357
+ */
358
+ public function isDefault()
359
+ {
360
+ return $this->default;
361
+ }
362
+
363
+ /**
364
+ * checks whether the card is expired based on the current date
365
+ *
366
+ * @return boolean
367
+ */
368
+ public function isExpired()
369
+ {
370
+ return $this->expired;
371
+ }
372
+
373
+ public static function delete($token)
374
+ {
375
+ self::_validateId($token);
376
+ Braintree_Http::delete('/payment_methods/' . $token);
377
+ return new Braintree_Result_Successful();
378
+ }
379
+
380
+ /**
381
+ * sets instance properties from an array of values
382
+ *
383
+ * @access protected
384
+ * @param array $creditCardAttribs array of creditcard data
385
+ * @return none
386
+ */
387
+ protected function _initialize($creditCardAttribs)
388
+ {
389
+ // set the attributes
390
+ $this->_attributes = $creditCardAttribs;
391
+
392
+ // map each address into its own object
393
+ $billingAddress = isset($creditCardAttribs['billingAddress']) ?
394
+ Braintree_Address::factory($creditCardAttribs['billingAddress']) :
395
+ null;
396
+
397
+ $subscriptionArray = array();
398
+ if (isset($creditCardAttribs['subscriptions'])) {
399
+ foreach ($creditCardAttribs['subscriptions'] AS $subscription) {
400
+ $subscriptionArray[] = Braintree_Subscription::factory($subscription);
401
+ }
402
+ }
403
+
404
+ $this->_set('subscriptions', $subscriptionArray);
405
+ $this->_set('billingAddress', $billingAddress);
406
+ $this->_set('expirationDate', $this->expirationMonth . '/' . $this->expirationYear);
407
+ $this->_set('maskedNumber', $this->bin . '******' . $this->last4);
408
+ }
409
+
410
+ /**
411
+ * returns false if comparing object is not a Braintree_CreditCard,
412
+ * or is a Braintree_CreditCard with a different id
413
+ *
414
+ * @param object $otherCreditCard customer to compare against
415
+ * @return boolean
416
+ */
417
+ public function isEqual($otherCreditCard)
418
+ {
419
+ return !($otherCreditCard instanceof Braintree_CreditCard) ? false : $this->token === $otherCreditCard->token;
420
+ }
421
+
422
+ private static function baseOptions()
423
+ {
424
+ return array('makeDefault', 'verificationMerchantAccountId', 'verifyCard', 'venmoSdkSession');
425
+ }
426
+
427
+ private static function baseSignature($options)
428
+ {
429
+ return array(
430
+ 'billingAddressId', 'cardholderName', 'cvv', 'number',
431
+ 'expirationDate', 'expirationMonth', 'expirationYear', 'token', 'venmoSdkPaymentMethodCode',
432
+ array('options' => $options),
433
+ array(
434
+ 'billingAddress' => array(
435
+ 'firstName',
436
+ 'lastName',
437
+ 'company',
438
+ 'countryCodeAlpha2',
439
+ 'countryCodeAlpha3',
440
+ 'countryCodeNumeric',
441
+ 'countryName',
442
+ 'extendedAddress',
443
+ 'locality',
444
+ 'region',
445
+ 'postalCode',
446
+ 'streetAddress'
447
+ ),
448
+ ),
449
+ );
450
+ }
451
+
452
+ public static function createSignature()
453
+ {
454
+ $options = self::baseOptions();
455
+ $options[] = "failOnDuplicatePaymentMethod";
456
+ $signature = self::baseSignature($options);
457
+ $signature[] = 'customerId';
458
+ return $signature;
459
+ }
460
+
461
+ public static function updateSignature()
462
+ {
463
+ $signature = self::baseSignature(self::baseOptions());
464
+
465
+ $updateExistingBillingSignature = array(
466
+ array(
467
+ 'options' => array(
468
+ 'updateExisting'
469
+ )
470
+ )
471
+ );
472
+
473
+ foreach($signature AS $key => $value) {
474
+ if(is_array($value) and array_key_exists('billingAddress', $value)) {
475
+ $signature[$key]['billingAddress'] = array_merge_recursive($value['billingAddress'], $updateExistingBillingSignature);
476
+ }
477
+ }
478
+
479
+ return $signature;
480
+ }
481
+
482
+ /**
483
+ * sends the create request to the gateway
484
+ *
485
+ * @ignore
486
+ * @param string $url
487
+ * @param array $params
488
+ * @return mixed
489
+ */
490
+ public static function _doCreate($url, $params)
491
+ {
492
+ $response = Braintree_Http::post($url, $params);
493
+
494
+ return self::_verifyGatewayResponse($response);
495
+ }
496
+
497
+ /**
498
+ * create a printable representation of the object as:
499
+ * ClassName[property=value, property=value]
500
+ * @return string
501
+ */
502
+ public function __toString()
503
+ {
504
+ return __CLASS__ . '[' .
505
+ Braintree_Util::attributesToString($this->_attributes) .']';
506
+ }
507
+
508
+ /**
509
+ * verifies that a valid credit card token is being used
510
+ * @ignore
511
+ * @param string $token
512
+ * @throws InvalidArgumentException
513
+ */
514
+ private static function _validateId($token = null)
515
+ {
516
+ if (empty($token)) {
517
+ throw new InvalidArgumentException(
518
+ 'expected credit card id to be set'
519
+ );
520
+ }
521
+ if (!preg_match('/^[0-9A-Za-z_-]+$/', $token)) {
522
+ throw new InvalidArgumentException(
523
+ $token . ' is an invalid credit card id.'
524
+ );
525
+ }
526
+ }
527
+
528
+ /**
529
+ * sends the update request to the gateway
530
+ *
531
+ * @ignore
532
+ * @param string $url
533
+ * @param array $params
534
+ * @return mixed
535
+ */
536
+ private static function _doUpdate($httpVerb, $url, $params)
537
+ {
538
+ $response = Braintree_Http::$httpVerb($url, $params);
539
+ return self::_verifyGatewayResponse($response);
540
+ }
541
+
542
+ /**
543
+ * generic method for validating incoming gateway responses
544
+ *
545
+ * creates a new Braintree_CreditCard object and encapsulates
546
+ * it inside a Braintree_Result_Successful object, or
547
+ * encapsulates a Braintree_Errors object inside a Result_Error
548
+ * alternatively, throws an Unexpected exception if the response is invalid.
549
+ *
550
+ * @ignore
551
+ * @param array $response gateway response values
552
+ * @return object Result_Successful or Result_Error
553
+ * @throws Braintree_Exception_Unexpected
554
+ */
555
+ private static function _verifyGatewayResponse($response)
556
+ {
557
+ if (isset($response['creditCard'])) {
558
+ // return a populated instance of Braintree_Address
559
+ return new Braintree_Result_Successful(
560
+ self::factory($response['creditCard'])
561
+ );
562
+ } else if (isset($response['apiErrorResponse'])) {
563
+ return new Braintree_Result_Error($response['apiErrorResponse']);
564
+ } else {
565
+ throw new Braintree_Exception_Unexpected(
566
+ "Expected address or apiErrorResponse"
567
+ );
568
+ }
569
+ }
570
+
571
+ /**
572
+ * factory method: returns an instance of Braintree_CreditCard
573
+ * to the requesting method, with populated properties
574
+ *
575
+ * @ignore
576
+ * @return object instance of Braintree_CreditCard
577
+ */
578
+ public static function factory($attributes)
579
+ {
580
+ $defaultAttributes = array(
581
+ 'bin' => '',
582
+ 'expirationMonth' => '',
583
+ 'expirationYear' => '',
584
+ 'last4' => '',
585
+ );
586
+
587
+ $instance = new self();
588
+ $instance->_initialize(array_merge($defaultAttributes, $attributes));
589
+ return $instance;
590
+ }
591
+ }
includes/lib/Braintree/Braintree/CreditCardVerification.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_CreditCardVerification extends Braintree_Result_CreditCardVerification
3
+ {
4
+ public static function factory($attributes)
5
+ {
6
+ $instance = new self($attributes);
7
+ return $instance;
8
+ }
9
+
10
+ public static function fetch($query, $ids)
11
+ {
12
+ $criteria = array();
13
+ foreach ($query as $term) {
14
+ $criteria[$term->name] = $term->toparam();
15
+ }
16
+ $criteria["ids"] = Braintree_CreditCardVerificationSearch::ids()->in($ids)->toparam();
17
+ $response = braintree_http::post('/verifications/advanced_search', array('search' => $criteria));
18
+
19
+ return braintree_util::extractattributeasarray(
20
+ $response['creditCardVerifications'],
21
+ 'verification'
22
+ );
23
+ }
24
+
25
+ public static function search($query)
26
+ {
27
+ $criteria = array();
28
+ foreach ($query as $term) {
29
+ $criteria[$term->name] = $term->toparam();
30
+ }
31
+
32
+ $response = braintree_http::post('/verifications/advanced_search_ids', array('search' => $criteria));
33
+ $pager = array(
34
+ 'className' => __CLASS__,
35
+ 'classMethod' => 'fetch',
36
+ 'methodArgs' => array($query)
37
+ );
38
+
39
+ return new Braintree_ResourceCollection($response, $pager);
40
+ }
41
+ }
includes/lib/Braintree/Braintree/CreditCardVerificationSearch.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_CreditCardVerificationSearch
3
+ {
4
+ static function id() { return new Braintree_TextNode('id'); }
5
+ static function creditCardCardholderName() { return new Braintree_TextNode('credit_card_cardholder_name'); }
6
+
7
+ static function creditCardExpirationDate() { return new Braintree_EqualityNode('credit_card_expiration_date'); }
8
+ static function creditCardNumber() { return new Braintree_PartialMatchNode('credit_card_number'); }
9
+
10
+ static function ids() { return new Braintree_MultipleValueNode('ids'); }
11
+
12
+ static function creditCardCardType()
13
+ {
14
+ return new Braintree_MultipleValueNode("credit_card_card_type", array(
15
+ Braintree_CreditCard::AMEX,
16
+ Braintree_CreditCard::CARTE_BLANCHE,
17
+ Braintree_CreditCard::CHINA_UNION_PAY,
18
+ Braintree_CreditCard::DINERS_CLUB_INTERNATIONAL,
19
+ Braintree_CreditCard::DISCOVER,
20
+ Braintree_CreditCard::JCB,
21
+ Braintree_CreditCard::LASER,
22
+ Braintree_CreditCard::MAESTRO,
23
+ Braintree_CreditCard::MASTER_CARD,
24
+ Braintree_CreditCard::SOLO,
25
+ Braintree_CreditCard::SWITCH_TYPE,
26
+ Braintree_CreditCard::VISA,
27
+ Braintree_CreditCard::UNKNOWN
28
+ ));
29
+ }
30
+
31
+
32
+ static function createdAt() { return new Braintree_RangeNode("created_at"); }
33
+ }
34
+
includes/lib/Braintree/Braintree/Customer.php ADDED
@@ -0,0 +1,562 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Customer module
4
+ *
5
+ * @package Braintree
6
+ * @category Resources
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Creates and manages Customers
12
+ *
13
+ * <b>== More information ==</b>
14
+ *
15
+ * For more detailed information on Customers, see {@link http://www.braintreepayments.com/gateway/customer-api http://www.braintreepaymentsolutions.com/gateway/customer-api}
16
+ *
17
+ * @package Braintree
18
+ * @category Resources
19
+ * @copyright 2010 Braintree Payment Solutions
20
+ *
21
+ * @property-read array $addresses
22
+ * @property-read string $company
23
+ * @property-read string $createdAt
24
+ * @property-read array $creditCards
25
+ * @property-read array $customFields custom fields passed with the request
26
+ * @property-read string $email
27
+ * @property-read string $fax
28
+ * @property-read string $firstName
29
+ * @property-read string $id
30
+ * @property-read string $lastName
31
+ * @property-read string $phone
32
+ * @property-read string $updatedAt
33
+ * @property-read string $website
34
+ */
35
+ class Braintree_Customer extends Braintree
36
+ {
37
+ public static function all()
38
+ {
39
+ $response = braintree_http::post('/customers/advanced_search_ids');
40
+ $pager = array(
41
+ 'className' => __CLASS__,
42
+ 'classMethod' => 'fetch',
43
+ 'methodArgs' => array(array())
44
+ );
45
+
46
+ return new Braintree_ResourceCollection($response, $pager);
47
+ }
48
+
49
+ public static function fetch($query, $ids)
50
+ {
51
+ $criteria = array();
52
+ foreach ($query as $term) {
53
+ $criteria[$term->name] = $term->toparam();
54
+ }
55
+ $criteria["ids"] = Braintree_CustomerSearch::ids()->in($ids)->toparam();
56
+ $response = braintree_http::post('/customers/advanced_search', array('search' => $criteria));
57
+
58
+ return braintree_util::extractattributeasarray(
59
+ $response['customers'],
60
+ 'customer'
61
+ );
62
+ }
63
+
64
+ /**
65
+ * Creates a customer using the given +attributes+. If <tt>:id</tt> is not passed,
66
+ * the gateway will generate it.
67
+ *
68
+ * <code>
69
+ * $result = Braintree_Customer::create(array(
70
+ * 'first_name' => 'John',
71
+ * 'last_name' => 'Smith',
72
+ * 'company' => 'Smith Co.',
73
+ * 'email' => 'john@smith.com',
74
+ * 'website' => 'www.smithco.com',
75
+ * 'fax' => '419-555-1234',
76
+ * 'phone' => '614-555-1234'
77
+ * ));
78
+ * if($result->success) {
79
+ * echo 'Created customer ' . $result->customer->id;
80
+ * } else {
81
+ * echo 'Could not create customer, see result->errors';
82
+ * }
83
+ * </code>
84
+ *
85
+ * @access public
86
+ * @param array $attribs
87
+ * @return object Result, either Successful or Error
88
+ */
89
+ public static function create($attribs = array())
90
+ {
91
+ Braintree_Util::verifyKeys(self::createSignature(), $attribs);
92
+ return self::_doCreate('/customers', array('customer' => $attribs));
93
+ }
94
+
95
+ /**
96
+ * attempts the create operation assuming all data will validate
97
+ * returns a Braintree_Customer object instead of a Result
98
+ *
99
+ * @access public
100
+ * @param array $attribs
101
+ * @return object
102
+ * @throws Braintree_Exception_ValidationError
103
+ */
104
+ public static function createNoValidate($attribs = array())
105
+ {
106
+ $result = self::create($attribs);
107
+ return self::returnObjectOrThrowException(__CLASS__, $result);
108
+ }
109
+ /**
110
+ * create a customer from a TransparentRedirect operation
111
+ *
112
+ * @access public
113
+ * @param array $attribs
114
+ * @return object
115
+ */
116
+ public static function createFromTransparentRedirect($queryString)
117
+ {
118
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::confirm", E_USER_NOTICE);
119
+ $params = Braintree_TransparentRedirect::parseAndValidateQueryString(
120
+ $queryString
121
+ );
122
+ return self::_doCreate(
123
+ '/customers/all/confirm_transparent_redirect_request',
124
+ array('id' => $params['id'])
125
+ );
126
+ }
127
+
128
+ /**
129
+ *
130
+ * @access public
131
+ * @param none
132
+ * @return string
133
+ */
134
+ public static function createCustomerUrl()
135
+ {
136
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::url", E_USER_NOTICE);
137
+ return Braintree_Configuration::merchantUrl() .
138
+ '/customers/all/create_via_transparent_redirect_request';
139
+ }
140
+
141
+
142
+ /**
143
+ * creates a full array signature of a valid create request
144
+ * @return array gateway create request format
145
+ */
146
+ public static function createSignature()
147
+ {
148
+
149
+ $creditCardSignature = Braintree_CreditCard::createSignature();
150
+ unset($creditCardSignature['customerId']);
151
+ $signature = array(
152
+ 'id', 'company', 'email', 'fax', 'firstName',
153
+ 'lastName', 'phone', 'website',
154
+ array('creditCard' => $creditCardSignature),
155
+ array('customFields' => array('_anyKey_')),
156
+ );
157
+ return $signature;
158
+ }
159
+
160
+ /**
161
+ * creates a full array signature of a valid update request
162
+ * @return array update request format
163
+ */
164
+ public static function updateSignature()
165
+ {
166
+ $creditCardSignature = Braintree_CreditCard::updateSignature();
167
+
168
+ foreach($creditCardSignature AS $key => $value) {
169
+ if(is_array($value) and array_key_exists('options', $value)) {
170
+ array_push($creditCardSignature[$key]['options'], 'updateExistingToken');
171
+ }
172
+ }
173
+
174
+ $signature = array(
175
+ 'id', 'company', 'email', 'fax', 'firstName',
176
+ 'lastName', 'phone', 'website',
177
+ array('creditCard' => $creditCardSignature),
178
+ array('customFields' => array('_anyKey_')),
179
+ );
180
+ return $signature;
181
+ }
182
+
183
+
184
+ /**
185
+ * find a customer by id
186
+ *
187
+ * @access public
188
+ * @param string id customer Id
189
+ * @return object Braintree_Customer
190
+ * @throws Braintree_Exception_NotFound
191
+ */
192
+ public static function find($id)
193
+ {
194
+ self::_validateId($id);
195
+ try {
196
+ $response = Braintree_Http::get('/customers/'.$id);
197
+ return self::factory($response['customer']);
198
+ } catch (Braintree_Exception_NotFound $e) {
199
+ throw new Braintree_Exception_NotFound(
200
+ 'customer with id ' . $id . ' not found'
201
+ );
202
+ }
203
+
204
+ }
205
+
206
+ /**
207
+ * credit a customer for the passed transaction
208
+ *
209
+ * @access public
210
+ * @param array $attribs
211
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
212
+ */
213
+ public static function credit($customerId, $transactionAttribs)
214
+ {
215
+ self::_validateId($customerId);
216
+ return Braintree_Transaction::credit(
217
+ array_merge($transactionAttribs,
218
+ array('customerId' => $customerId)
219
+ )
220
+ );
221
+ }
222
+
223
+ /**
224
+ * credit a customer, assuming validations will pass
225
+ *
226
+ * returns a Braintree_Transaction object on success
227
+ *
228
+ * @access public
229
+ * @param array $attribs
230
+ * @return object Braintree_Transaction
231
+ * @throws Braintree_Exception_ValidationError
232
+ */
233
+ public static function creditNoValidate($customerId, $transactionAttribs)
234
+ {
235
+ $result = self::credit($customerId, $transactionAttribs);
236
+ return self::returnObjectOrThrowException('Braintree_Transaction', $result);
237
+ }
238
+
239
+ /**
240
+ * delete a customer by id
241
+ *
242
+ * @param string $customerId
243
+ */
244
+ public static function delete($customerId)
245
+ {
246
+ self::_validateId($customerId);
247
+ Braintree_Http::delete('/customers/' . $customerId);
248
+ return new Braintree_Result_Successful();
249
+ }
250
+
251
+ /**
252
+ * create a new sale for a customer
253
+ *
254
+ * @param string $customerId
255
+ * @param array $transactionAttribs
256
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
257
+ * @see Braintree_Transaction::sale()
258
+ */
259
+ public static function sale($customerId, $transactionAttribs)
260
+ {
261
+ self::_validateId($customerId);
262
+ return Braintree_Transaction::sale(
263
+ array_merge($transactionAttribs,
264
+ array('customerId' => $customerId)
265
+ )
266
+ );
267
+ }
268
+
269
+ /**
270
+ * create a new sale for a customer, assuming validations will pass
271
+ *
272
+ * returns a Braintree_Transaction object on success
273
+ * @access public
274
+ * @param string $customerId
275
+ * @param array $transactionAttribs
276
+ * @return object Braintree_Transaction
277
+ * @throws Braintree_Exception_ValidationsFailed
278
+ * @see Braintree_Transaction::sale()
279
+ */
280
+ public static function saleNoValidate($customerId, $transactionAttribs)
281
+ {
282
+ $result = self::sale($customerId, $transactionAttribs);
283
+ return self::returnObjectOrThrowException('Braintree_Transaction', $result);
284
+ }
285
+
286
+ /**
287
+ * Returns a ResourceCollection of customers matching the search query.
288
+ *
289
+ * If <b>query</b> is a string, the search will be a basic search.
290
+ * If <b>query</b> is a hash, the search will be an advanced search.
291
+ * For more detailed information and examples, see {@link http://www.braintreepayments.com/gateway/customer-api#searching http://www.braintreepaymentsolutions.com/gateway/customer-api}
292
+ *
293
+ * @param mixed $query search query
294
+ * @param array $options options such as page number
295
+ * @return object Braintree_ResourceCollection
296
+ * @throws InvalidArgumentException
297
+ */
298
+ public static function search($query)
299
+ {
300
+ $criteria = array();
301
+ foreach ($query as $term) {
302
+ $criteria[$term->name] = $term->toparam();
303
+ }
304
+
305
+ $response = braintree_http::post('/customers/advanced_search_ids', array('search' => $criteria));
306
+ $pager = array(
307
+ 'className' => __CLASS__,
308
+ 'classMethod' => 'fetch',
309
+ 'methodArgs' => array($query)
310
+ );
311
+
312
+ return new Braintree_ResourceCollection($response, $pager);
313
+ }
314
+
315
+ /**
316
+ * updates the customer record
317
+ *
318
+ * if calling this method in static context, customerId
319
+ * is the 2nd attribute. customerId is not sent in object context.
320
+ *
321
+ * @access public
322
+ * @param array $attributes
323
+ * @param string $customerId (optional)
324
+ * @return object Braintree_Result_Successful or Braintree_Result_Error
325
+ */
326
+ public static function update($customerId, $attributes)
327
+ {
328
+ Braintree_Util::verifyKeys(self::updateSignature(), $attributes);
329
+ self::_validateId($customerId);
330
+ return self::_doUpdate(
331
+ 'put',
332
+ '/customers/' . $customerId,
333
+ array('customer' => $attributes)
334
+ );
335
+ }
336
+
337
+ /**
338
+ * update a customer record, assuming validations will pass
339
+ *
340
+ * if calling this method in static context, customerId
341
+ * is the 2nd attribute. customerId is not sent in object context.
342
+ * returns a Braintree_Customer object on success
343
+ *
344
+ * @access public
345
+ * @param array $attributes
346
+ * @param string $customerId
347
+ * @return object Braintree_Customer
348
+ * @throws Braintree_Exception_ValidationsFailed
349
+ */
350
+ public static function updateNoValidate($customerId, $attributes)
351
+ {
352
+ $result = self::update($customerId, $attributes);
353
+ return self::returnObjectOrThrowException(__CLASS__, $result);
354
+ }
355
+ /**
356
+ *
357
+ * @access public
358
+ * @param none
359
+ * @return string
360
+ */
361
+ public static function updateCustomerUrl()
362
+ {
363
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::url", E_USER_NOTICE);
364
+ return Braintree_Configuration::merchantUrl() .
365
+ '/customers/all/update_via_transparent_redirect_request';
366
+ }
367
+
368
+ /**
369
+ * update a customer from a TransparentRedirect operation
370
+ *
371
+ * @access public
372
+ * @param array $attribs
373
+ * @return object
374
+ */
375
+ public static function updateFromTransparentRedirect($queryString)
376
+ {
377
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::confirm", E_USER_NOTICE);
378
+ $params = Braintree_TransparentRedirect::parseAndValidateQueryString(
379
+ $queryString
380
+ );
381
+ return self::_doUpdate(
382
+ 'post',
383
+ '/customers/all/confirm_transparent_redirect_request',
384
+ array('id' => $params['id'])
385
+ );
386
+ }
387
+
388
+ /* instance methods */
389
+
390
+ /**
391
+ * sets instance properties from an array of values
392
+ *
393
+ * @ignore
394
+ * @access protected
395
+ * @param array $customerAttribs array of customer data
396
+ * @return none
397
+ */
398
+ protected function _initialize($customerAttribs)
399
+ {
400
+ // set the attributes
401
+ $this->_attributes = $customerAttribs;
402
+
403
+ // map each address into its own object
404
+ $addressArray = array();
405
+ if (isset($customerAttribs['addresses'])) {
406
+
407
+ foreach ($customerAttribs['addresses'] AS $address) {
408
+ $addressArray[] = Braintree_Address::factory($address);
409
+ }
410
+ }
411
+ $this->_set('addresses', $addressArray);
412
+
413
+ // map each creditcard into its own object
414
+ $ccArray = array();
415
+ if (isset($customerAttribs['creditCards'])) {
416
+ foreach ($customerAttribs['creditCards'] AS $creditCard) {
417
+ $ccArray[] = Braintree_CreditCard::factory($creditCard);
418
+ }
419
+ }
420
+ $this->_set('creditCards', $ccArray);
421
+
422
+ }
423
+
424
+ /**
425
+ * returns a string representation of the customer
426
+ * @return string
427
+ */
428
+ public function __toString()
429
+ {
430
+ return __CLASS__ . '[' .
431
+ Braintree_Util::attributesToString($this->_attributes) .']';
432
+ }
433
+
434
+ /**
435
+ * returns false if comparing object is not a Braintree_Customer,
436
+ * or is a Braintree_Customer with a different id
437
+ *
438
+ * @param object $otherCust customer to compare against
439
+ * @return boolean
440
+ */
441
+ public function isEqual($otherCust)
442
+ {
443
+ return !($otherCust instanceof Braintree_Customer) ? false : $this->id === $otherCust->id;
444
+ }
445
+
446
+ /* private class properties */
447
+
448
+ /**
449
+ * @access protected
450
+ * @var array registry of customer data
451
+ */
452
+ protected $_attributes = array(
453
+ 'addresses' => '',
454
+ 'company' => '',
455
+ 'creditCards' => '',
456
+ 'email' => '',
457
+ 'fax' => '',
458
+ 'firstName' => '',
459
+ 'id' => '',
460
+ 'lastName' => '',
461
+ 'phone' => '',
462
+ 'createdAt' => '',
463
+ 'updatedAt' => '',
464
+ 'website' => '',
465
+ );
466
+
467
+ /**
468
+ * sends the create request to the gateway
469
+ *
470
+ * @ignore
471
+ * @param string $url
472
+ * @param array $params
473
+ * @return mixed
474
+ */
475
+ public static function _doCreate($url, $params)
476
+ {
477
+ $response = Braintree_Http::post($url, $params);
478
+
479
+ return self::_verifyGatewayResponse($response);
480
+ }
481
+
482
+ /**
483
+ * verifies that a valid customer id is being used
484
+ * @ignore
485
+ * @param string customer id
486
+ * @throws InvalidArgumentException
487
+ */
488
+ private static function _validateId($id = null) {
489
+ if (empty($id)) {
490
+ throw new InvalidArgumentException(
491
+ 'expected customer id to be set'
492
+ );
493
+ }
494
+ if (!preg_match('/^[0-9A-Za-z_-]+$/', $id)) {
495
+ throw new InvalidArgumentException(
496
+ $id . ' is an invalid customer id.'
497
+ );
498
+ }
499
+ }
500
+
501
+
502
+ /* private class methods */
503
+
504
+ /**
505
+ * sends the update request to the gateway
506
+ *
507
+ * @ignore
508
+ * @param string $url
509
+ * @param array $params
510
+ * @return mixed
511
+ */
512
+ private static function _doUpdate($httpVerb, $url, $params)
513
+ {
514
+ $response = Braintree_Http::$httpVerb($url, $params);
515
+
516
+ return self::_verifyGatewayResponse($response);
517
+ }
518
+
519
+ /**
520
+ * generic method for validating incoming gateway responses
521
+ *
522
+ * creates a new Braintree_Customer object and encapsulates
523
+ * it inside a Braintree_Result_Successful object, or
524
+ * encapsulates a Braintree_Errors object inside a Result_Error
525
+ * alternatively, throws an Unexpected exception if the response is invalid.
526
+ *
527
+ * @ignore
528
+ * @param array $response gateway response values
529
+ * @return object Result_Successful or Result_Error
530
+ * @throws Braintree_Exception_Unexpected
531
+ */
532
+ private static function _verifyGatewayResponse($response)
533
+ {
534
+ if (isset($response['customer'])) {
535
+ // return a populated instance of Braintree_Customer
536
+ return new Braintree_Result_Successful(
537
+ self::factory($response['customer'])
538
+ );
539
+ } else if (isset($response['apiErrorResponse'])) {
540
+ return new Braintree_Result_Error($response['apiErrorResponse']);
541
+ } else {
542
+ throw new Braintree_Exception_Unexpected(
543
+ "Expected customer or apiErrorResponse"
544
+ );
545
+ }
546
+ }
547
+
548
+ /**
549
+ * factory method: returns an instance of Braintree_Customer
550
+ * to the requesting method, with populated properties
551
+ *
552
+ * @ignore
553
+ * @return object instance of Braintree_Customer
554
+ */
555
+ public static function factory($attributes)
556
+ {
557
+ $instance = new self();
558
+ $instance->_initialize($attributes);
559
+ return $instance;
560
+ }
561
+
562
+ }
includes/lib/Braintree/Braintree/CustomerSearch.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_CustomerSearch
3
+ {
4
+ static function addressCountryName() { return new Braintree_TextNode('address_country_name'); }
5
+ static function addressExtendedAddress() { return new Braintree_TextNode('address_extended_address'); }
6
+ static function addressFirstName() { return new Braintree_TextNode('address_first_name'); }
7
+ static function addressLastName() { return new Braintree_TextNode('address_last_name'); }
8
+ static function addressLocality() { return new Braintree_TextNode('address_locality'); }
9
+ static function addressPostalCode() { return new Braintree_TextNode('address_postal_code'); }
10
+ static function addressRegion() { return new Braintree_TextNode('address_region'); }
11
+ static function addressStreetAddress() { return new Braintree_TextNode('address_street_address'); }
12
+ static function cardholderName() { return new Braintree_TextNode('cardholder_name'); }
13
+ static function company() { return new Braintree_TextNode('company'); }
14
+ static function email() { return new Braintree_TextNode('email'); }
15
+ static function fax() { return new Braintree_TextNode('fax'); }
16
+ static function firstName() { return new Braintree_TextNode('first_name'); }
17
+ static function id() { return new Braintree_TextNode('id'); }
18
+ static function lastName() { return new Braintree_TextNode('last_name'); }
19
+ static function paymentMethodToken() { return new Braintree_TextNode('payment_method_token'); }
20
+ static function paymentMethodTokenWithDuplicates() { return new Braintree_IsNode('payment_method_token_with_duplicates'); }
21
+ static function phone() { return new Braintree_TextNode('phone'); }
22
+ static function website() { return new Braintree_TextNode('website'); }
23
+
24
+ static function creditCardExpirationDate() { return new Braintree_EqualityNode('credit_card_expiration_date'); }
25
+ static function creditCardNumber() { return new Braintree_PartialMatchNode('credit_card_number'); }
26
+
27
+ static function ids() { return new Braintree_MultipleValueNode('ids'); }
28
+
29
+ static function createdAt() { return new Braintree_RangeNode("created_at"); }
30
+ }
31
+
includes/lib/Braintree/Braintree/Descriptor.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ class Braintree_Descriptor extends Braintree_Instance
3
+ {
4
+ }
includes/lib/Braintree/Braintree/Digest.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Digest encryption module
4
+ *
5
+ * @copyright 2010 Braintree Payment Solutions
6
+ */
7
+
8
+ /**
9
+ * Digest creates an HMAC-SHA1 hash for encrypting messages
10
+ *
11
+ * @copyright 2010 Braintree Payment Solutions
12
+ */
13
+ class Braintree_Digest
14
+ {
15
+ public static function hexDigest($string)
16
+ {
17
+ if(function_exists('hash_hmac')) {
18
+ return self::_builtInHmacSha1($string, Braintree_Configuration::privateKey());
19
+ } else {
20
+ return self::_hmacSha1($string, Braintree_Configuration::privateKey());
21
+ }
22
+ }
23
+
24
+ public static function secureCompare($left, $right)
25
+ {
26
+ if (strlen($left) != strlen($right)) {
27
+ return false;
28
+ }
29
+
30
+ $leftBytes = unpack("C*", $left);
31
+ $rightBytes = unpack("C*", $right);
32
+
33
+ $result = 0;
34
+ for ($i = 0; $i < strlen($left); $i++) {
35
+ $result = $result | ($left[$i] ^ $right[$i]);
36
+ }
37
+ return $result == 0;
38
+ }
39
+
40
+ public static function _builtInHmacSha1($message, $key)
41
+ {
42
+ return hash_hmac('sha1', $message, sha1(Braintree_Configuration::privateKey(), true));
43
+ }
44
+
45
+ public static function _hmacSha1($message, $key)
46
+ {
47
+ $pack = 'H40';
48
+ $keyDigest = sha1($key,true);
49
+ $innerPad = str_repeat(chr(0x36), 64);
50
+ $outerPad = str_repeat(chr(0x5C), 64);
51
+
52
+ for ($i = 0; $i < 20; $i++) {
53
+ $innerPad{$i} = $keyDigest{$i} ^ $innerPad{$i};
54
+ $outerPad{$i} = $keyDigest{$i} ^ $outerPad{$i};
55
+ }
56
+
57
+ return sha1($outerPad.pack($pack, sha1($innerPad.$message)));
58
+ }
59
+ }
includes/lib/Braintree/Braintree/Discount.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_Discount extends Braintree_Modification
3
+ {
4
+ public static function all()
5
+ {
6
+ $response = Braintree_Http::get('/discounts');
7
+
8
+ $discounts = array("discount" => $response['discounts']);
9
+
10
+ return Braintree_Util::extractAttributeAsArray(
11
+ $discounts,
12
+ 'discount'
13
+ );
14
+ }
15
+ }
includes/lib/Braintree/Braintree/EqualityNode.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_EqualityNode extends Braintree_IsNode
4
+ {
5
+ function isNot($value)
6
+ {
7
+ $this->searchTerms['is_not'] = strval($value);
8
+ return $this;
9
+ }
10
+ }
includes/lib/Braintree/Braintree/Error/Codes.php ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * validation Error codes and messages
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Errors
7
+ * @category Validation
8
+ * @copyright 2010 Braintree Payment Solutions
9
+ */
10
+
11
+ /**
12
+ *
13
+ * Validation Error codes and messages
14
+ *
15
+ * ErrorCodes class provides constants for validation errors.
16
+ * The constants should be used to check for a specific validation
17
+ * error in a ValidationErrorCollection.
18
+ * The error messages returned from the server may change,
19
+ * but the codes will remain the same.
20
+ *
21
+ * @package Braintree
22
+ * @subpackage Errors
23
+ * @category Validation
24
+ * @copyright 2010 Braintree Payment Solutions
25
+ */
26
+ class Braintree_Error_Codes
27
+ {
28
+ const ADDRESS_CANNOT_BE_BLANK = '81801';
29
+ const ADDRESS_COMPANY_IS_TOO_LONG = '81802';
30
+ const ADDRESS_COUNTRY_CODE_ALPHA2_IS_NOT_ACCEPTED = '91814';
31
+ const ADDRESS_COUNTRY_CODE_ALPHA3_IS_NOT_ACCEPTED = '91816';
32
+ const ADDRESS_COUNTRY_CODE_NUMERIC_IS_NOT_ACCEPTED = '91817';
33
+ const ADDRESS_COUNTRY_NAME_IS_NOT_ACCEPTED = '91803';
34
+ const ADDRESS_EXTENDED_ADDRESS_IS_TOO_LONG = '81804';
35
+ const ADDRESS_FIRST_NAME_IS_TOO_LONG = '81805';
36
+ const ADDRESS_INCONSISTENT_COUNTRY = '91815';
37
+ const ADDRESS_LAST_NAME_IS_TOO_LONG = '81806';
38
+ const ADDRESS_LOCALITY_IS_TOO_LONG = '81807';
39
+ const ADDRESS_POSTAL_CODE_INVALID_CHARACTERS = '81813';
40
+ const ADDRESS_POSTAL_CODE_IS_REQUIRED = '81808';
41
+ const ADDRESS_POSTAL_CODE_IS_TOO_LONG = '81809';
42
+ const ADDRESS_REGION_IS_TOO_LONG = '81810';
43
+ const ADDRESS_STREET_ADDRESS_IS_REQUIRED = '81811';
44
+ const ADDRESS_STREET_ADDRESS_IS_TOO_LONG = '81812';
45
+ const ADDRESS_TOO_MANY_ADDRESSES_PER_CUSTOMER = '91818';
46
+
47
+ const CREDIT_CARD_BILLING_ADDRESS_CONFLICT = '91701';
48
+ const CREDIT_CARD_BILLING_ADDRESS_ID_IS_INVALID = '91702';
49
+ const CREDIT_CARD_CARDHOLDER_NAME_IS_TOO_LONG = '81723';
50
+ const CREDIT_CARD_CREDIT_CARD_TYPE_IS_NOT_ACCEPTED = '81703';
51
+ const CREDIT_CARD_CREDIT_CARD_TYPE_IS_NOT_ACCEPTED_BY_SUBSCRIPTION_MERCHANT_ACCOUNT = '81718';
52
+ const CREDIT_CARD_CUSTOMER_ID_IS_INVALID = '91705';
53
+ const CREDIT_CARD_CUSTOMER_ID_IS_REQUIRED = '91704';
54
+ const CREDIT_CARD_CVV_IS_INVALID = '81707';
55
+ const CREDIT_CARD_CVV_IS_REQUIRED = '81706';
56
+ const CREDIT_CARD_DUPLICATE_CARD_EXISTS = '81724';
57
+ const CREDIT_CARD_EXPIRATION_DATE_CONFLICT = '91708';
58
+ const CREDIT_CARD_EXPIRATION_DATE_IS_INVALID = '81710';
59
+ const CREDIT_CARD_EXPIRATION_DATE_IS_REQUIRED = '81709';
60
+ const CREDIT_CARD_EXPIRATION_DATE_YEAR_IS_INVALID = '81711';
61
+ const CREDIT_CARD_EXPIRATION_MONTH_IS_INVALID = '81712';
62
+ const CREDIT_CARD_EXPIRATION_YEAR_IS_INVALID = '81713';
63
+ const CREDIT_CARD_NUMBER_INVALID_LENGTH = '81716';
64
+ const CREDIT_CARD_NUMBER_IS_INVALID = '81715';
65
+ const CREDIT_CARD_NUMBER_IS_REQUIRED = '81714';
66
+ const CREDIT_CARD_NUMBER_MUST_BE_TEST_NUMBER = '81717';
67
+ const CREDIT_CARD_OPTIONS_UPDATE_EXISTING_TOKEN_IS_INVALID = '91723';
68
+ const CREDIT_CARD_TOKEN_INVALID = '91718';
69
+ const CREDIT_CARD_TOKEN_IS_IN_USE = '91719';
70
+ const CREDIT_CARD_TOKEN_IS_NOT_ALLOWED = '91721';
71
+ const CREDIT_CARD_TOKEN_IS_REQUIRED = '91722';
72
+ const CREDIT_CARD_TOKEN_IS_TOO_LONG = '91720';
73
+
74
+ const CUSTOMER_COMPANY_IS_TOO_LONG = '81601';
75
+ const CUSTOMER_CUSTOM_FIELD_IS_INVALID = '91602';
76
+ const CUSTOMER_CUSTOM_FIELD_IS_TOO_LONG = '81603';
77
+ const CUSTOMER_EMAIL_IS_INVALID = '81604';
78
+ const CUSTOMER_EMAIL_IS_REQUIRED = '81606';
79
+ const CUSTOMER_EMAIL_IS_TOO_LONG = '81605';
80
+ const CUSTOMER_FAX_IS_TOO_LONG = '81607';
81
+ const CUSTOMER_FIRST_NAME_IS_TOO_LONG = '81608';
82
+ const CUSTOMER_ID_IS_INVAILD = '91610'; //Deprecated
83
+ const CUSTOMER_ID_IS_INVALID = '91610';
84
+ const CUSTOMER_ID_IS_IN_USE = '91609';
85
+ const CUSTOMER_ID_IS_NOT_ALLOWED = '91611';
86
+ const CUSTOMER_ID_IS_REQUIRED = '91613';
87
+ const CUSTOMER_ID_IS_TOO_LONG = '91612';
88
+ const CUSTOMER_LAST_NAME_IS_TOO_LONG = '81613';
89
+ const CUSTOMER_PHONE_IS_TOO_LONG = '81614';
90
+ const CUSTOMER_WEBSITE_IS_INVALID = '81616';
91
+ const CUSTOMER_WEBSITE_IS_TOO_LONG = '81615';
92
+
93
+ const DESCRIPTOR_NAME_FORMAT_IS_INVALID = '92201';
94
+ const DESCRIPTOR_PHONE_FORMAT_IS_INVALID = '92202';
95
+
96
+ const SETTLEMENT_BATCH_SUMMARY_SETTLEMENT_DATE_IS_INVALID = '82302';
97
+ const SETTLEMENT_BATCH_SUMMARY_SETTLEMENT_DATE_IS_REQUIRED = '82301';
98
+ const SETTLEMENT_BATCH_SUMMARY_CUSTOM_FIELD_IS_INVALID = '82303';
99
+
100
+ const SUBSCRIPTION_BILLING_DAY_OF_MONTH_CANNOT_BE_UPDATED = '91918';
101
+ const SUBSCRIPTION_BILLING_DAY_OF_MONTH_IS_INVALID = '91914';
102
+ const SUBSCRIPTION_BILLING_DAY_OF_MONTH_MUST_BE_NUMERIC = '91913';
103
+ const SUBSCRIPTION_CANNOT_ADD_DUPLICATE_ADDON_OR_DISCOUNT = '91911';
104
+ const SUBSCRIPTION_CANNOT_EDIT_CANCELED_SUBSCRIPTION = '81901';
105
+ const SUBSCRIPTION_CANNOT_EDIT_EXPIRED_SUBSCRIPTION = '81910';
106
+ const SUBSCRIPTION_CANNOT_EDIT_PRICE_CHANGING_FIELDS_ON_PAST_DUE_SUBSCRIPTION = '91920';
107
+ const SUBSCRIPTION_FIRST_BILLING_DATE_CANNOT_BE_IN_THE_PAST = '91916';
108
+ const SUBSCRIPTION_FIRST_BILLING_DATE_CANNOT_BE_UPDATED = '91919';
109
+ const SUBSCRIPTION_FIRST_BILLING_DATE_IS_INVALID = '91915';
110
+ const SUBSCRIPTION_ID_IS_IN_USE = '81902';
111
+ const SUBSCRIPTION_INCONSISTENT_NUMBER_OF_BILLING_CYCLES = '91908';
112
+ const SUBSCRIPTION_INCONSISTENT_START_DATE = '91917';
113
+ const SUBSCRIPTION_INVALID_REQUEST_FORMAT = '91921';
114
+ const SUBSCRIPTION_MERCHANT_ACCOUNT_ID_IS_INVALID = '91901';
115
+ const SUBSCRIPTION_MISMATCH_CURRENCY_ISO_CODE = '91923';
116
+ const SUBSCRIPTION_NUMBER_OF_BILLING_CYCLES_CANNOT_BE_BLANK = '91912';
117
+ const SUBSCRIPTION_NUMBER_OF_BILLING_CYCLES_IS_TOO_SMALL = '91909';
118
+ const SUBSCRIPTION_NUMBER_OF_BILLING_CYCLES_MUST_BE_GREATER_THAN_ZERO = '91907';
119
+ const SUBSCRIPTION_NUMBER_OF_BILLING_CYCLES_MUST_BE_NUMERIC = '91906';
120
+ const SUBSCRIPTION_PAYMENT_METHOD_TOKEN_CARD_TYPE_IS_NOT_ACCEPTED = '91902';
121
+ const SUBSCRIPTION_PAYMENT_METHOD_TOKEN_IS_INVALID = '91903';
122
+ const SUBSCRIPTION_PAYMENT_METHOD_TOKEN_NOT_ASSOCIATED_WITH_CUSTOMER = '91905';
123
+ const SUBSCRIPTION_PLAN_BILLING_FREQUENCY_CANNOT_BE_UPDATED = '91922';
124
+ const SUBSCRIPTION_PLAN_ID_IS_INVALID = '91904';
125
+ const SUBSCRIPTION_PRICE_CANNOT_BE_BLANK = '81903';
126
+ const SUBSCRIPTION_PRICE_FORMAT_IS_INVALID = '81904';
127
+ const SUBSCRIPTION_PRICE_IS_TOO_LARGE = '81923';
128
+ const SUBSCRIPTION_STATUS_IS_CANCELED = '81905';
129
+ const SUBSCRIPTION_TOKEN_FORMAT_IS_INVALID = '81906';
130
+ const SUBSCRIPTION_TRIAL_DURATION_FORMAT_IS_INVALID = '81907';
131
+ const SUBSCRIPTION_TRIAL_DURATION_IS_REQUIRED = '81908';
132
+ const SUBSCRIPTION_TRIAL_DURATION_UNIT_IS_INVALID = '81909';
133
+
134
+ const SUBSCRIPTION_MODIFICATION_AMOUNT_CANNOT_BE_BLANK = '92003';
135
+ const SUBSCRIPTION_MODIFICATION_AMOUNT_IS_INVALID = '92002';
136
+ const SUBSCRIPTION_MODIFICATION_AMOUNT_IS_TOO_LARGE = '92023';
137
+ const SUBSCRIPTION_MODIFICATION_CANNOT_EDIT_MODIFICATIONS_ON_PAST_DUE_SUBSCRIPTION = '92022';
138
+ const SUBSCRIPTION_MODIFICATION_CANNOT_UPDATE_AND_REMOVE = '92015';
139
+ const SUBSCRIPTION_MODIFICATION_EXISTING_ID_IS_INCORRECT_KIND = '92020';
140
+ const SUBSCRIPTION_MODIFICATION_EXISTING_ID_IS_INVALID = '92011';
141
+ const SUBSCRIPTION_MODIFICATION_EXISTING_ID_IS_REQUIRED = '92012';
142
+ const SUBSCRIPTION_MODIFICATION_ID_TO_REMOVE_IS_INCORRECT_KIND = '92021';
143
+ const SUBSCRIPTION_MODIFICATION_ID_TO_REMOVE_IS_NOT_PRESENT = '92016';
144
+ const SUBSCRIPTION_MODIFICATION_INCONSISTENT_NUMBER_OF_BILLING_CYCLES = '92018';
145
+ const SUBSCRIPTION_MODIFICATION_INHERITED_FROM_ID_IS_INVALID = '92013';
146
+ const SUBSCRIPTION_MODIFICATION_INHERITED_FROM_ID_IS_REQUIRED = '92014';
147
+ const SUBSCRIPTION_MODIFICATION_NUMBER_OF_BILLING_CYCLES_CANNOT_BE_BLANK = '92017';
148
+ const SUBSCRIPTION_MODIFICATION_NUMBER_OF_BILLING_CYCLES_IS_INVALID = '92005';
149
+ const SUBSCRIPTION_MODIFICATION_NUMBER_OF_BILLING_CYCLES_MUST_BE_GREATER_THAN_ZERO = '92019';
150
+ const SUBSCRIPTION_MODIFICATION_QUANTITY_CANNOT_BE_BLANK = '92004';
151
+ const SUBSCRIPTION_MODIFICATION_QUANTITY_IS_INVALID = '92001';
152
+ const SUBSCRIPTION_MODIFICATION_QUANTITY_MUST_BE_GREATER_THAN_ZERO = '92010';
153
+
154
+ const TRANSACTION_AMOUNT_CANNOT_BE_NEGATIVE = '81501';
155
+ const TRANSACTION_AMOUNT_IS_INVALID = '81503';
156
+ const TRANSACTION_AMOUNT_IS_REQUIRED = '81502';
157
+ const TRANSACTION_AMOUNT_IS_TOO_LARGE = '81528';
158
+ const TRANSACTION_AMOUNT_MUST_BE_GREATER_THAN_ZERO = '81531';
159
+ const TRANSACTION_BILLING_ADDRESS_CONFLICT = '91530';
160
+ const TRANSACTION_CANNOT_BE_VOIDED = '91504';
161
+ const TRANSACTION_CANNOT_CLONE_CREDIT = '91543';
162
+ const TRANSACTION_CANNOT_CLONE_TRANSACTION_WITH_VAULT_CREDIT_CARD = '91540';
163
+ const TRANSACTION_CANNOT_CLONE_UNSUCCESSFUL_TRANSACTION = '91542';
164
+ const TRANSACTION_CANNOT_CLONE_VOICE_AUTHORIZATIONS = '91541';
165
+ const TRANSACTION_CANNOT_REFUND_CREDIT = '91505';
166
+ const TRANSACTION_CANNOT_REFUND_UNLESS_SETTLED = '91506';
167
+ const TRANSACTION_CANNOT_REFUND_WITH_SUSPENDED_MERCHANT_ACCOUNT = '91538';
168
+ const TRANSACTION_CANNOT_SUBMIT_FOR_SETTLEMENT = '91507';
169
+ const TRANSACTION_CHANNEL_IS_TOO_LONG = '91550';
170
+ const TRANSACTION_CREDIT_CARD_IS_REQUIRED = '91508';
171
+ const TRANSACTION_CUSTOMER_DEFAULT_PAYMENT_METHOD_CARD_TYPE_IS_NOT_ACCEPTED = '81509';
172
+ const TRANSACTION_CUSTOMER_DOES_NOT_HAVE_CREDIT_CARD = '91511';
173
+ const TRANSACTION_CUSTOMER_ID_IS_INVALID = '91510';
174
+ const TRANSACTION_CUSTOM_FIELD_IS_INVALID = '91526';
175
+ const TRANSACTION_CUSTOM_FIELD_IS_TOO_LONG = '81527';
176
+ const TRANSACTION_HAS_ALREADY_BEEN_REFUNDED = '91512';
177
+ const TRANSACTION_MERCHANT_ACCOUNT_DOES_NOT_SUPPORT_REFUNDS = '91547';
178
+ const TRANSACTION_MERCHANT_ACCOUNT_ID_IS_INVALID = '91513';
179
+ const TRANSACTION_MERCHANT_ACCOUNT_IS_SUSPENDED = '91514';
180
+ const TRANSACTION_MERCHANT_ACCOUNT_NAME_IS_INVALID = '91513'; //Deprecated
181
+ const TRANSACTION_OPTIONS_SUBMIT_FOR_SETTLEMENT_IS_REQUIRED_FOR_CLONING = '91544';
182
+ const TRANSACTION_OPTIONS_VAULT_IS_DISABLED = '91525';
183
+ const TRANSACTION_ORDER_ID_IS_TOO_LONG = '91501';
184
+ const TRANSACTION_PAYMENT_METHOD_CONFLICT = '91515';
185
+ const TRANSACTION_PAYMENT_METHOD_DOES_NOT_BELONG_TO_CUSTOMER = '91516';
186
+ const TRANSACTION_PAYMENT_METHOD_DOES_NOT_BELONG_TO_SUBSCRIPTION = '91527';
187
+ const TRANSACTION_PAYMENT_METHOD_TOKEN_CARD_TYPE_IS_NOT_ACCEPTED = '91517';
188
+ const TRANSACTION_PAYMENT_METHOD_TOKEN_IS_INVALID = '91518';
189
+ const TRANSACTION_PROCESSOR_AUTHORIZATION_CODE_CANNOT_BE_SET = '91519';
190
+ const TRANSACTION_PROCESSOR_AUTHORIZATION_CODE_IS_INVALID = '81520';
191
+ const TRANSACTION_PROCESSOR_DOES_NOT_SUPPORT_CREDITS = '91546';
192
+ const TRANSACTION_PROCESSOR_DOES_NOT_SUPPORT_VOICE_AUTHORIZATIONS = '91545';
193
+ const TRANSACTION_PURCHASE_ORDER_NUMBER_IS_TOO_LONG = '91537';
194
+ const TRANSACTION_PURCHASE_ORDER_NUMBER_IS_INVALID = '91548';
195
+ const TRANSACTION_REFUND_AMOUNT_IS_TOO_LARGE = '91521';
196
+ const TRANSACTION_SETTLEMENT_AMOUNT_IS_TOO_LARGE = '91522';
197
+ const TRANSACTION_SUBSCRIPTION_DOES_NOT_BELONG_TO_CUSTOMER = '91529';
198
+ const TRANSACTION_SUBSCRIPTION_ID_IS_INVALID = '91528';
199
+ const TRANSACTION_SUBSCRIPTION_STATUS_MUST_BE_PAST_DUE = '91531';
200
+ const TRANSACTION_TAX_AMOUNT_CANNOT_BE_NEGATIVE = '81534';
201
+ const TRANSACTION_TAX_AMOUNT_FORMAT_IS_INVALID = '81535';
202
+ const TRANSACTION_TAX_AMOUNT_IS_TOO_LARGE = '81536';
203
+ const TRANSACTION_TYPE_IS_INVALID = '91523';
204
+ const TRANSACTION_TYPE_IS_REQUIRED = '91524';
205
+ const TRANSACTION_UNSUPPORTED_VOICE_AUTHORIZATION = '91539';
206
+ }
includes/lib/Braintree/Braintree/Error/ErrorCollection.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * Error handler
5
+ *
6
+ * @package Braintree
7
+ * @subpackage Errors
8
+ * @category Errors
9
+ * @copyright 2010 Braintree Payment Solutions
10
+ */
11
+
12
+
13
+ /**
14
+ * Handles validation errors
15
+ *
16
+ * Contains a read-only property $error which is a ValidationErrorCollection
17
+ *
18
+ * @package Braintree
19
+ * @subpackage Errors
20
+ * @category Errors
21
+ * @copyright 2010 Braintree Payment Solutions
22
+ *
23
+ * @property-read object $errors
24
+ */
25
+ class Braintree_Error_ErrorCollection
26
+ {
27
+ private $_errors;
28
+
29
+ public function __construct($errorData)
30
+ {
31
+ $this->_errors =
32
+ new Braintree_Error_ValidationErrorCollection($errorData);
33
+ }
34
+
35
+
36
+ /**
37
+ * Returns all of the validation errors at all levels of nesting in a single, flat array.
38
+ */
39
+ public function deepAll()
40
+ {
41
+ return $this->_errors->deepAll();
42
+ }
43
+
44
+ /**
45
+ * Returns the total number of validation errors at all levels of nesting. For example,
46
+ *if creating a customer with a credit card and a billing address, and each of the customer,
47
+ * credit card, and billing address has 1 error, this method will return 3.
48
+ *
49
+ * @return int size
50
+ */
51
+ public function deepSize()
52
+ {
53
+ $size = $this->_errors->deepSize();
54
+ return $size;
55
+ }
56
+
57
+ /**
58
+ * return errors for the passed key name
59
+ *
60
+ * @param string $key
61
+ * @return mixed
62
+ */
63
+ public function forKey($key)
64
+ {
65
+ return $this->_errors->forKey($key);
66
+ }
67
+
68
+ /**
69
+ * return errors for the passed html field.
70
+ * For example, $result->errors->onHtmlField("transaction[customer][last_name]")
71
+ *
72
+ * @param string $field
73
+ * @return array
74
+ */
75
+ public function onHtmlField($field)
76
+ {
77
+ $pieces = preg_split("/[\[\]]+/", $field, 0, PREG_SPLIT_NO_EMPTY);
78
+ $errors = $this;
79
+ foreach(array_slice($pieces, 0, -1) as $key) {
80
+ $errors = $errors->forKey(Braintree_Util::delimiterToCamelCase($key));
81
+ if (!isset($errors)) { return array(); }
82
+ }
83
+ $finalKey = Braintree_Util::delimiterToCamelCase(end($pieces));
84
+ return $errors->onAttribute($finalKey);
85
+ }
86
+
87
+ /**
88
+ * Returns the errors at the given nesting level (see forKey) in a single, flat array:
89
+ *
90
+ * <code>
91
+ * $result = Braintree_Customer::create(...);
92
+ * $customerErrors = $result->errors->forKey('customer')->shallowAll();
93
+ * </code>
94
+ */
95
+ public function shallowAll()
96
+ {
97
+ return $this->_errors->shallowAll();
98
+ }
99
+
100
+ /**
101
+ *
102
+ * @ignore
103
+ */
104
+ public function __get($name)
105
+ {
106
+ $varName = "_$name";
107
+ return isset($this->$varName) ? $this->$varName : null;
108
+ }
109
+
110
+ /**
111
+ *
112
+ * @ignore
113
+ */
114
+ public function __toString()
115
+ {
116
+ return sprintf('%s', $this->_errors);
117
+ }
118
+ }
includes/lib/Braintree/Braintree/Error/Validation.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * error object returned as part of a validation error collection
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Error
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * error object returned as part of a validation error collection
12
+ * provides read-only access to $attribute, $code, and $message
13
+ *
14
+ * <b>== More information ==</b>
15
+ *
16
+ * For more detailed information on Validation errors, see {@link http://www.braintreepayments.com/gateway/validation-errors http://www.braintreepaymentsolutions.com/gateway/validation-errors}
17
+ *
18
+ * @package Braintree
19
+ * @subpackage Error
20
+ * @copyright 2010 Braintree Payment Solutions
21
+ *
22
+ * @property-read string $attribute
23
+ * @property-read string $code
24
+ * @property-read string $message
25
+ */
26
+ class Braintree_Error_Validation
27
+ {
28
+ private $_attribute;
29
+ private $_code;
30
+ private $_message;
31
+
32
+ /**
33
+ * @ignore
34
+ * @param array $attributes
35
+ */
36
+ public function __construct($attributes)
37
+ {
38
+ $this->_initializeFromArray($attributes);
39
+ }
40
+ /**
41
+ * initializes instance properties from the keys/values of an array
42
+ * @ignore
43
+ * @access protected
44
+ * @param array $attributes array of properties to set - single level
45
+ * @return none
46
+ */
47
+ private function _initializeFromArray($attributes)
48
+ {
49
+ foreach($attributes AS $name => $value) {
50
+ $varName = "_$name";
51
+ $this->$varName = Braintree_Util::delimiterToCamelCase($value, '_');
52
+ }
53
+ }
54
+
55
+ /**
56
+ *
57
+ * @ignore
58
+ */
59
+ public function __get($name)
60
+ {
61
+ $varName = "_$name";
62
+ return isset($this->$varName) ? $this->$varName : null;
63
+ }
64
+ }
includes/lib/Braintree/Braintree/Error/ValidationErrorCollection.php ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * collection of errors enumerating all validation errors for a given request
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Error
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * collection of errors enumerating all validation errors for a given request
12
+ *
13
+ * <b>== More information ==</b>
14
+ *
15
+ * For more detailed information on Validation errors, see {@link http://www.braintreepayments.com/gateway/validation-errors http://www.braintreepaymentsolutions.com/gateway/validation-errors}
16
+ *
17
+ * @package Braintree
18
+ * @subpackage Error
19
+ * @copyright 2010 Braintree Payment Solutions
20
+ *
21
+ * @property-read array $errors
22
+ * @property-read array $nested
23
+ */
24
+ class Braintree_Error_ValidationErrorCollection extends Braintree_Collection
25
+ {
26
+ private $_errors = array();
27
+ private $_nested = array();
28
+
29
+ /**
30
+ * @ignore
31
+ */
32
+ public function __construct($data)
33
+ {
34
+ foreach($data AS $key => $errorData)
35
+ // map errors to new collections recursively
36
+ if ($key == 'errors') {
37
+ foreach ($errorData AS $error) {
38
+ $this->_errors[] = new Braintree_Error_Validation($error);
39
+ }
40
+ } else {
41
+ $this->_nested[$key] = new Braintree_Error_ValidationErrorCollection($errorData);
42
+ }
43
+
44
+ }
45
+
46
+ public function deepAll()
47
+ {
48
+ $validationErrors = array_merge(array(), $this->_errors);
49
+ foreach($this->_nested as $nestedErrors)
50
+ {
51
+ $validationErrors = array_merge($validationErrors, $nestedErrors->deepAll());
52
+ }
53
+ return $validationErrors;
54
+ }
55
+
56
+ public function deepSize()
57
+ {
58
+ $total = sizeof($this->_errors);
59
+ foreach($this->_nested as $_nestedErrors)
60
+ {
61
+ $total = $total + $_nestedErrors->deepSize();
62
+ }
63
+ return $total;
64
+ }
65
+
66
+ public function forIndex($index)
67
+ {
68
+ return $this->forKey("index" . $index);
69
+ }
70
+
71
+ public function forKey($key)
72
+ {
73
+ return isset($this->_nested[$key]) ? $this->_nested[$key] : null;
74
+ }
75
+
76
+ public function onAttribute($attribute)
77
+ {
78
+ $matches = array();
79
+ foreach ($this->_errors AS $key => $error) {
80
+ if($error->attribute == $attribute) {
81
+ $matches[] = $error;
82
+ }
83
+ }
84
+ return $matches;
85
+ }
86
+
87
+
88
+ public function shallowAll()
89
+ {
90
+ return $this->_errors;
91
+ }
92
+
93
+ /**
94
+ *
95
+ * @ignore
96
+ */
97
+ public function __get($name)
98
+ {
99
+ $varName = "_$name";
100
+ return isset($this->$varName) ? $this->$varName : null;
101
+ }
102
+
103
+ /**
104
+ * @ignore
105
+ */
106
+ public function __toString()
107
+ {
108
+ $output = array();
109
+
110
+ // TODO: implement scope
111
+ if (!empty($this->_errors)) {
112
+ $output[] = $this->_inspect($this->_errors);
113
+ }
114
+ if (!empty($this->_nested)) {
115
+ foreach ($this->_nested AS $key => $values) {
116
+ $output[] = $this->_inspect($this->_nested);
117
+ }
118
+ }
119
+ return join(', ', $output);
120
+ }
121
+
122
+ /**
123
+ * @ignore
124
+ */
125
+ private function _inspect($errors, $scope = null)
126
+ {
127
+ $eOutput = '[' . __CLASS__ . '/errors:[';
128
+ foreach($errors AS $error => $errorObj) {
129
+ $outputErrs[] = "({$errorObj->error['code']} {$errorObj->error['message']})";
130
+ }
131
+ $eOutput .= join(', ', $outputErrs) . ']]';
132
+
133
+ return $eOutput;
134
+ }
135
+ }
includes/lib/Braintree/Braintree/Exception.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * super class for all Braintree exceptions
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+
11
+ /**
12
+ * super class for all Braintree exceptions
13
+ *
14
+ * @package Braintree
15
+ * @subpackage Exception
16
+ * @copyright 2010 Braintree Payment Solutions
17
+ */
18
+ class Braintree_Exception extends Exception
19
+ {
20
+ }
includes/lib/Braintree/Braintree/Exception/Authentication.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when authentication fails
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Raised when authentication fails.
12
+ * This may be caused by an incorrect Braintree_Configuration
13
+ *
14
+ * @package Braintree
15
+ * @subpackage Exception
16
+ * @copyright 2010 Braintree Payment Solutions
17
+ */
18
+ class Braintree_Exception_Authentication extends Braintree_Exception
19
+ {
20
+
21
+ }
includes/lib/Braintree/Braintree/Exception/Authorization.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when authorization fails
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+
11
+ /**
12
+ * Raised when the API key being used is not authorized to perform
13
+ * the attempted action according to the roles assigned to the user
14
+ * who owns the API key.
15
+ *
16
+ * @package Braintree
17
+ * @subpackage Exception
18
+ * @copyright 2010 Braintree Payment Solutions
19
+ */
20
+ class Braintree_Exception_Authorization extends Braintree_Exception
21
+ {
22
+
23
+ }
includes/lib/Braintree/Braintree/Exception/Configuration.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * raised when the Braintree library is not completely configured
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Raised when the Braintree library is not completely configured.
12
+ *
13
+ * @package Braintree
14
+ * @subpackage Exception
15
+ * @see Braintree_Configuration
16
+ */
17
+ class Braintree_Exception_Configuration extends Braintree_Exception
18
+ {
19
+
20
+ }
includes/lib/Braintree/Braintree/Exception/DownForMaintenance.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when the gateway is down for maintenance
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Raised when the gateway is down for maintenance.
12
+ *
13
+ * @package Braintree
14
+ * @subpackage Exception
15
+ * @copyright 2010 Braintree Payment Solutions
16
+ */
17
+ class Braintree_Exception_DownForMaintenance extends Braintree_Exception
18
+ {
19
+
20
+ }
includes/lib/Braintree/Braintree/Exception/ForgedQueryString.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when a suspected forged query string is present
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Raised from methods that confirm transparent request requests
12
+ * when the given query string cannot be verified. This may indicate
13
+ * an attempted hack on the merchant's transparent redirect
14
+ * confirmation URL.
15
+ *
16
+ * @package Braintree
17
+ * @subpackage Exception
18
+ * @copyright 2010 Braintree Payment Solutions
19
+ */
20
+ class Braintree_Exception_ForgedQueryString extends Braintree_Exception
21
+ {
22
+
23
+ }
includes/lib/Braintree/Braintree/Exception/InvalidSignature.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+ class Braintree_Exception_InvalidSignature extends Braintree_Exception
3
+ {
4
+
5
+ }
includes/lib/Braintree/Braintree/Exception/NotFound.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when a record coult not be found
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Raised when a record could not be found.
12
+ *
13
+ * @package Braintree
14
+ * @subpackage Exception
15
+ * @copyright 2010 Braintree Payment Solutions
16
+ */
17
+ class Braintree_Exception_NotFound extends Braintree_Exception
18
+ {
19
+
20
+ }
includes/lib/Braintree/Braintree/Exception/SSLCaFileNotFound.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when the SSL CaFile is not found.
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2011 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Raised when the SSL CaFile is not found.
12
+ *
13
+ * @package Braintree
14
+ * @subpackage Exception
15
+ * @copyright 2011 Braintree Payment Solutions
16
+ */
17
+ class Braintree_Exception_SSLCaFileNotFound extends Braintree_Exception
18
+ {
19
+
20
+ }
includes/lib/Braintree/Braintree/Exception/SSLCertificate.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when the SSL certificate fails verification.
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Raised when the SSL certificate fails verification.
12
+ *
13
+ * @package Braintree
14
+ * @subpackage Exception
15
+ * @copyright 2010 Braintree Payment Solutions
16
+ */
17
+ class Braintree_Exception_SSLCertificate extends Braintree_Exception
18
+ {
19
+
20
+ }
includes/lib/Braintree/Braintree/Exception/ServerError.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when an unexpected server error occurs.
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Raised when an unexpected server error occurs.
12
+ *
13
+ * @package Braintree
14
+ * @subpackage Exception
15
+ * @copyright 2010 Braintree Payment Solutions
16
+ */
17
+ class Braintree_Exception_ServerError extends Braintree_Exception
18
+ {
19
+
20
+ }
includes/lib/Braintree/Braintree/Exception/Unexpected.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when an unexpected error occurs
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Raised when an error occurs that the client library is not built to handle.
12
+ * This shouldn't happen.
13
+ *
14
+ * @package Braintree
15
+ * @subpackage Exception
16
+ * @copyright 2010 Braintree Payment Solutions
17
+ */
18
+ class Braintree_Exception_Unexpected extends Braintree_Exception
19
+ {
20
+
21
+ }
includes/lib/Braintree/Braintree/Exception/UpgradeRequired.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised when a client library must be upgraded.
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+ class Braintree_Exception_UpgradeRequired extends Braintree_Exception
10
+ {
11
+
12
+ }
includes/lib/Braintree/Braintree/Exception/ValidationsFailed.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Raised from non-validating exceptions when validations fail
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Exception
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Raised from non-validating methods when gateway validations fail.
12
+ *
13
+ * @package Braintree
14
+ * @subpackage Exception
15
+ * @copyright 2010 Braintree Payment Solutions
16
+ */
17
+ class Braintree_Exception_ValidationsFailed extends Braintree_Exception
18
+ {
19
+
20
+ }
21
+
includes/lib/Braintree/Braintree/Http.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree HTTP Client
4
+ *
5
+ * @copyright 2010 Braintree Payment Solutions
6
+ */
7
+
8
+ /**
9
+ * processes Http requests using curl
10
+ *
11
+ * @copyright 2010 Braintree Payment Solutions
12
+ */
13
+ class Braintree_Http
14
+ {
15
+ public static function delete($path)
16
+ {
17
+ $response = self::_doRequest('DELETE', $path);
18
+ if($response['status'] === 200) {
19
+ return true;
20
+ } else {
21
+ Braintree_Util::throwStatusCodeException($response['status']);
22
+ }
23
+ }
24
+
25
+ public static function get($path)
26
+ {
27
+ $response = self::_doRequest('GET', $path);
28
+ if($response['status'] === 200) {
29
+ return Braintree_Xml::buildArrayFromXml($response['body']);
30
+ } else {
31
+ Braintree_Util::throwStatusCodeException($response['status']);
32
+ }
33
+ }
34
+
35
+ public static function post($path, $params = null)
36
+ {
37
+ $response = self::_doRequest('POST', $path, self::_buildXml($params));
38
+ $responseCode = $response['status'];
39
+ if($responseCode === 200 || $responseCode === 201 || $responseCode === 422) {
40
+ return Braintree_Xml::buildArrayFromXml($response['body']);
41
+ } else {
42
+ Braintree_Util::throwStatusCodeException($responseCode);
43
+ }
44
+ }
45
+
46
+ public static function put($path, $params = null)
47
+ {
48
+ $response = self::_doRequest('PUT', $path, self::_buildXml($params));
49
+ $responseCode = $response['status'];
50
+ if($responseCode === 200 || $responseCode === 201 || $responseCode === 422) {
51
+ return Braintree_Xml::buildArrayFromXml($response['body']);
52
+ } else {
53
+ Braintree_Util::throwStatusCodeException($responseCode);
54
+ }
55
+ }
56
+
57
+ private static function _buildXml($params)
58
+ {
59
+ return empty($params) ? null : Braintree_Xml::buildXmlFromArray($params);
60
+ }
61
+
62
+ private static function _doRequest($httpVerb, $path, $requestBody = null)
63
+ {
64
+ $curl = curl_init();
65
+ curl_setopt($curl, CURLOPT_TIMEOUT, 60);
66
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $httpVerb);
67
+ curl_setopt($curl, CURLOPT_URL, Braintree_Configuration::merchantUrl() . $path);
68
+ curl_setopt($curl, CURLOPT_ENCODING, 'gzip');
69
+ curl_setopt($curl, CURLOPT_HTTPHEADER, array(
70
+ 'Accept: application/xml',
71
+ 'Content-Type: application/xml',
72
+ 'User-Agent: Braintree PHP Library ' . Braintree_Version::get(),
73
+ 'X-ApiVersion: ' . Braintree_Configuration::API_VERSION
74
+ ));
75
+ curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
76
+ curl_setopt($curl, CURLOPT_USERPWD, Braintree_Configuration::publicKey() . ':' . Braintree_Configuration::privateKey());
77
+ // curl_setopt($curl, CURLOPT_VERBOSE, true);
78
+ if (Braintree_Configuration::sslOn()) {
79
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
80
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
81
+ curl_setopt($curl, CURLOPT_CAINFO, Braintree_Configuration::caFile());
82
+ }
83
+
84
+ if(!empty($requestBody)) {
85
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $requestBody);
86
+ }
87
+
88
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
89
+ $response = curl_exec($curl);
90
+ $httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
91
+ curl_close($curl);
92
+ if (Braintree_Configuration::sslOn()) {
93
+ if ($httpStatus == 0) {
94
+ throw new Braintree_Exception_SSLCertificate();
95
+ }
96
+ }
97
+ return array('status' => $httpStatus, 'body' => $response);
98
+ }
99
+ }
includes/lib/Braintree/Braintree/Instance.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Class Instance template
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Utility
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * abstract instance template for various objects
12
+ *
13
+ * @package Braintree
14
+ * @subpackage Utility
15
+ * @copyright 2010 Braintree Payment Solutions
16
+ * @abstract
17
+ */
18
+ abstract class Braintree_Instance
19
+ {
20
+ /**
21
+ *
22
+ * @param array $aAttribs
23
+ */
24
+ public function __construct($attributes)
25
+ {
26
+ if (!empty($attributes)) {
27
+ $this->_initializeFromArray($attributes);
28
+ }
29
+ }
30
+
31
+
32
+ /**
33
+ * returns private/nonexistent instance properties
34
+ * @access public
35
+ * @param var $name property name
36
+ * @return mixed contents of instance properties
37
+ */
38
+ public function __get($name)
39
+ {
40
+ if (array_key_exists($name, $this->_attributes)) {
41
+ return $this->_attributes[$name];
42
+ } else {
43
+ trigger_error('Undefined property on ' . get_class($this) . ': ' . $name, E_USER_NOTICE);
44
+ return null;
45
+ }
46
+ }
47
+
48
+ /**
49
+ * create a printable representation of the object as:
50
+ * ClassName[property=value, property=value]
51
+ * @return var
52
+ */
53
+ public function __toString()
54
+ {
55
+ $objOutput = Braintree_Util::implodeAssociativeArray($this->_attributes);
56
+ return get_class($this) .'['.$objOutput.']';
57
+ }
58
+ /**
59
+ * initializes instance properties from the keys/values of an array
60
+ * @ignore
61
+ * @access protected
62
+ * @param <type> $aAttribs array of properties to set - single level
63
+ * @return none
64
+ */
65
+ private function _initializeFromArray($attributes)
66
+ {
67
+ $this->_attributes = $attributes;
68
+ }
69
+
70
+ }
includes/lib/Braintree/Braintree/IsNode.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_IsNode
4
+ {
5
+ function __construct($name)
6
+ {
7
+ $this->name = $name;
8
+ $this->searchTerms = array();
9
+ }
10
+
11
+ function is($value)
12
+ {
13
+ $this->searchTerms['is'] = strval($value);
14
+ return $this;
15
+ }
16
+
17
+ function toParam()
18
+ {
19
+ return $this->searchTerms;
20
+ }
21
+ }
22
+
includes/lib/Braintree/Braintree/KeyValueNode.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_KeyValueNode
4
+ {
5
+ function __construct($name)
6
+ {
7
+ $this->name = $name;
8
+ $this->searchTerm = True;
9
+
10
+ }
11
+
12
+ function is($value)
13
+ {
14
+ $this->searchTerm = $value;
15
+ return $this;
16
+ }
17
+
18
+ function toParam()
19
+ {
20
+ return $this->searchTerm;
21
+ }
22
+ }
includes/lib/Braintree/Braintree/Modification.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_Modification extends Braintree
3
+ {
4
+ protected function _initialize($attributes)
5
+ {
6
+ $this->_attributes = $attributes;
7
+
8
+ $addOnArray = array();
9
+ if (isset($attributes['addOns'])) {
10
+ foreach ($attributes['addOns'] AS $addOn) {
11
+ $addOnArray[] = Braintree_addOn::factory($addOn);
12
+ }
13
+ }
14
+ $this->_attributes['addOns'] = $addOnArray;
15
+ }
16
+
17
+ public static function factory($attributes)
18
+ {
19
+ $instance = new self();
20
+ $instance->_initialize($attributes);
21
+ return $instance;
22
+ }
23
+ }
includes/lib/Braintree/Braintree/MultipleValueNode.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_MultipleValueNode
4
+ {
5
+ function __construct($name, $allowedValues = array())
6
+ {
7
+ $this->name = $name;
8
+ $this->items = array();
9
+ $this->allowedValues = $allowedValues;
10
+ }
11
+
12
+ function in($values)
13
+ {
14
+ $bad_values = array_diff($values, $this->allowedValues);
15
+ if (count($this->allowedValues) > 0 && count($bad_values) > 0) {
16
+ $message = 'Invalid argument(s) for ' . $this->name . ':';
17
+ foreach ($bad_values AS $bad_value) {
18
+ $message .= ' ' . $bad_value;
19
+ }
20
+
21
+ throw new InvalidArgumentException($message);
22
+ }
23
+
24
+ $this->items = $values;
25
+ return $this;
26
+ }
27
+
28
+ function is($value)
29
+ {
30
+ return $this->in(array($value));
31
+ }
32
+
33
+ function toParam()
34
+ {
35
+ return $this->items;
36
+ }
37
+ }
includes/lib/Braintree/Braintree/MultipleValueOrTextNode.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_MultipleValueOrTextNode extends Braintree_MultipleValueNode
4
+ {
5
+ function __construct($name)
6
+ {
7
+ parent::__construct($name);
8
+ $this->textNode = new Braintree_TextNode($name);
9
+ }
10
+
11
+ function contains($value)
12
+ {
13
+ $this->textNode->contains($value);
14
+ return $this;
15
+ }
16
+
17
+ function endsWith($value)
18
+ {
19
+ $this->textNode->endsWith($value);
20
+ return $this;
21
+ }
22
+
23
+ function is($value)
24
+ {
25
+ $this->textNode->is($value);
26
+ return $this;
27
+ }
28
+
29
+ function isNot($value)
30
+ {
31
+ $this->textNode->isNot($value);
32
+ return $this;
33
+ }
34
+
35
+ function startsWith($value)
36
+ {
37
+ $this->textNode->startsWith($value);
38
+ return $this;
39
+ }
40
+
41
+ function toParam()
42
+ {
43
+ return array_merge(parent::toParam(), $this->textNode->toParam());
44
+ }
45
+ }
46
+
includes/lib/Braintree/Braintree/PartialMatchNode.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_PartialMatchNode extends Braintree_EqualityNode
4
+ {
5
+ function startsWith($value)
6
+ {
7
+ $this->searchTerms["starts_with"] = strval($value);
8
+ return $this;
9
+ }
10
+
11
+ function endsWith($value)
12
+ {
13
+ $this->searchTerms["ends_with"] = strval($value);
14
+ return $this;
15
+ }
16
+ }
includes/lib/Braintree/Braintree/Plan.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_Plan extends Braintree
3
+ {
4
+ public static function all()
5
+ {
6
+ $response = Braintree_Http::get('/plans');
7
+ if (key_exists('plans', $response)){
8
+ $plans = array("plan" => $response['plans']);
9
+ } else {
10
+ $plans = array("plan" => array());
11
+ }
12
+
13
+ return Braintree_Util::extractAttributeAsArray(
14
+ $plans,
15
+ 'plan'
16
+ );
17
+ }
18
+
19
+ public static function factory($attributes)
20
+ {
21
+ $instance = new self();
22
+ $instance->_initialize($attributes);
23
+
24
+ return $instance;
25
+ }
26
+
27
+ protected function _initialize($attributes)
28
+ {
29
+ $this->_attributes = $attributes;
30
+
31
+ $addOnArray = array();
32
+ if (isset($attributes['addOns'])) {
33
+ foreach ($attributes['addOns'] AS $addOn) {
34
+ $addOnArray[] = Braintree_AddOn::factory($addOn);
35
+ }
36
+ }
37
+ $this->_attributes['addOns'] = $addOnArray;
38
+
39
+ $discountArray = array();
40
+ if (isset($attributes['discounts'])) {
41
+ foreach ($attributes['discounts'] AS $discount) {
42
+ $discountArray[] = Braintree_Discount::factory($discount);
43
+ }
44
+ }
45
+ $this->_attributes['discounts'] = $discountArray;
46
+
47
+ $planArray = array();
48
+ if (isset($attributes['plans'])) {
49
+ foreach ($attributes['plans'] AS $plan) {
50
+ $planArray[] = Braintree_Plan::factory($plan);
51
+ }
52
+ }
53
+ $this->_attributes['plans'] = $planArray;
54
+ }
55
+ }
includes/lib/Braintree/Braintree/RangeNode.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_RangeNode
4
+ {
5
+ function __construct($name)
6
+ {
7
+ $this->name = $name;
8
+ $this->searchTerms = array();
9
+ }
10
+
11
+ function greaterThanOrEqualTo($value)
12
+ {
13
+ $this->searchTerms['min'] = $value;
14
+ return $this;
15
+ }
16
+
17
+ function lessThanOrEqualTo($value)
18
+ {
19
+ $this->searchTerms['max'] = $value;
20
+ return $this;
21
+ }
22
+
23
+ function is($value)
24
+ {
25
+ $this->searchTerms['is'] = $value;
26
+ return $this;
27
+ }
28
+
29
+ function between($min, $max)
30
+ {
31
+ return $this->greaterThanOrEqualTo($min)->lessThanOrEqualTo($max);
32
+ }
33
+
34
+ function toParam()
35
+ {
36
+ return $this->searchTerms;
37
+ }
38
+ }
includes/lib/Braintree/Braintree/ResourceCollection.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree ResourceCollection
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Utility
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * ResourceCollection is a container object for result data
12
+ *
13
+ * stores and retrieves search results and aggregate data
14
+ *
15
+ * example:
16
+ * <code>
17
+ * $result = Braintree_Customer::all();
18
+ *
19
+ * foreach($result as $transaction) {
20
+ * print_r($transaction->id);
21
+ * }
22
+ * </code>
23
+ *
24
+ * @package Braintree
25
+ * @subpackage Utility
26
+ * @copyright 2010 Braintree Payment Solutions
27
+ */
28
+ class Braintree_ResourceCollection implements Iterator
29
+ {
30
+ private $_index;
31
+ private $_batchIndex;
32
+ private $_items;
33
+ private $_pageSize;
34
+ private $_pager;
35
+
36
+ /**
37
+ * set up the resource collection
38
+ *
39
+ * expects an array of attributes with literal keys
40
+ *
41
+ * @param array $attributes
42
+ * @param array $pagerAttribs
43
+ */
44
+ public function __construct($response, $pager)
45
+ {
46
+ $this->_pageSize = $response["searchResults"]["pageSize"];
47
+ $this->_ids = $response["searchResults"]["ids"];
48
+ $this->_pager = $pager;
49
+ }
50
+
51
+ /**
52
+ * returns the current item when iterating with foreach
53
+ */
54
+ public function current()
55
+ {
56
+ return $this->_items[$this->_index];
57
+ }
58
+
59
+ /**
60
+ * returns the first item in the collection
61
+ *
62
+ * @return mixed
63
+ */
64
+ public function firstItem()
65
+ {
66
+ $ids = $this->_ids;
67
+ $page = $this->_getPage(array($ids[0]));
68
+ return $page[0];
69
+ }
70
+
71
+ public function key()
72
+ {
73
+ return null;
74
+ }
75
+
76
+ /**
77
+ * advances to the next item in the collection when iterating with foreach
78
+ */
79
+ public function next()
80
+ {
81
+ ++$this->_index;
82
+ }
83
+
84
+ /**
85
+ * rewinds thtestIterateOverResultse collection to the first item when iterating with foreach
86
+ */
87
+ public function rewind()
88
+ {
89
+ $this->_batchIndex = 0;
90
+ $this->_getNextPage();
91
+ }
92
+
93
+ /**
94
+ * returns whether the current item is valid when iterating with foreach
95
+ */
96
+ public function valid()
97
+ {
98
+ if ($this->_index == count($this->_items) && $this->_batchIndex < count($this->_ids)) {
99
+ $this->_getNextPage();
100
+ }
101
+
102
+ if ($this->_index < count($this->_items)) {
103
+ return true;
104
+ } else {
105
+ return false;
106
+ }
107
+ }
108
+
109
+ public function maximumCount()
110
+ {
111
+ return count($this->_ids);
112
+ }
113
+
114
+ private function _getNextPage()
115
+ {
116
+ if (empty($this->_ids))
117
+ {
118
+ $this->_items = array();
119
+ }
120
+ else
121
+ {
122
+ $this->_items = $this->_getPage(array_slice($this->_ids, $this->_batchIndex, $this->_pageSize));
123
+ $this->_batchIndex += $this->_pageSize;
124
+ $this->_index = 0;
125
+ }
126
+ }
127
+
128
+ /**
129
+ * requests the next page of results for the collection
130
+ *
131
+ * @return none
132
+ */
133
+ private function _getPage($ids)
134
+ {
135
+ $className = $this->_pager['className'];
136
+ $classMethod = $this->_pager['classMethod'];
137
+ $methodArgs = array();
138
+ foreach ($this->_pager['methodArgs'] as $arg) {
139
+ array_push($methodArgs, $arg);
140
+ }
141
+ array_push($methodArgs, $ids);
142
+
143
+ return call_user_func_array(
144
+ array($className, $classMethod),
145
+ $methodArgs
146
+ );
147
+ }
148
+ }
includes/lib/Braintree/Braintree/Result/CreditCardVerification.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Credit Card Verification Result
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Result
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Braintree Credit Card Verification Result
12
+ *
13
+ * This object is returned as part of an Error Result; it provides
14
+ * access to the credit card verification data from the gateway
15
+ *
16
+ *
17
+ * @package Braintree
18
+ * @subpackage Result
19
+ * @copyright 2010 Braintree Payment Solutions
20
+ *
21
+ * @property-read string $avsErrorResponseCode
22
+ * @property-read string $avsPostalCodeResponseCode
23
+ * @property-read string $avsStreetAddressResponseCode
24
+ * @property-read string $cvvResponseCode
25
+ * @property-read string $status
26
+ *
27
+ */
28
+ class Braintree_Result_CreditCardVerification
29
+ {
30
+ // Status
31
+ const FAILED = 'failed';
32
+ const GATEWAY_REJECTED = 'gateway_rejected';
33
+ const PROCESSOR_DECLINED = 'processor_declined';
34
+ const VERIFIED = 'verified';
35
+
36
+ private $_attributes;
37
+ private $_avsErrorResponseCode;
38
+ private $_avsPostalCodeResponseCode;
39
+ private $_avsStreetAddressResponseCode;
40
+ private $_cvvResponseCode;
41
+ private $_gatewayRejectionReason;
42
+ private $_status;
43
+
44
+ /**
45
+ * @ignore
46
+ */
47
+ public function __construct($attributes)
48
+ {
49
+ $this->_initializeFromArray($attributes);
50
+ }
51
+ /**
52
+ * initializes instance properties from the keys/values of an array
53
+ * @ignore
54
+ * @access protected
55
+ * @param <type> $aAttribs array of properties to set - single level
56
+ * @return none
57
+ */
58
+ private function _initializeFromArray($attributes)
59
+ {
60
+ $this->_attributes = $attributes;
61
+ foreach($attributes AS $name => $value) {
62
+ $varName = "_$name";
63
+ $this->$varName = $value;
64
+ // $this->$varName = Braintree_Util::delimiterToCamelCase($value, '_');
65
+ }
66
+ }
67
+ /**
68
+ *
69
+ * @ignore
70
+ */
71
+ public function __get($name)
72
+ {
73
+ $varName = "_$name";
74
+ return isset($this->$varName) ? $this->$varName : null;
75
+ }
76
+
77
+ /**
78
+ * returns a string representation of the customer
79
+ * @return string
80
+ */
81
+ public function __toString()
82
+ {
83
+ return __CLASS__ . '[' .
84
+ Braintree_Util::attributesToString($this->_attributes) .']';
85
+ }
86
+ }
includes/lib/Braintree/Braintree/Result/Error.php ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Error Result
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Result
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Braintree Error Result
12
+ *
13
+ * An Error Result will be returned from gateway methods when
14
+ * the gateway responds with an error. It will provide access
15
+ * to the original request.
16
+ * For example, when voiding a transaction, Error Result will
17
+ * respond to the void request if it failed:
18
+ *
19
+ * <code>
20
+ * $result = Braintree_Transaction::void('abc123');
21
+ * if ($result->success) {
22
+ * // Successful Result
23
+ * } else {
24
+ * // Braintree_Result_Error
25
+ * }
26
+ * </code>
27
+ *
28
+ * @package Braintree
29
+ * @subpackage Result
30
+ * @copyright 2010 Braintree Payment Solutions
31
+ *
32
+ * @property-read array $params original passed params
33
+ * @property-read object $errors Braintree_Error_ErrorCollection
34
+ * @property-read object $creditCardVerification credit card verification data
35
+ */
36
+ class Braintree_Result_Error extends Braintree
37
+ {
38
+ /**
39
+ *
40
+ * @var boolean always false
41
+ */
42
+ public $success = false;
43
+
44
+ /**
45
+ * return original value for a field
46
+ * For example, if a user tried to submit 'invalid-email' in the html field transaction[customer][email],
47
+ * $result->valueForHtmlField("transaction[customer][email]") would yield "invalid-email"
48
+ *
49
+ * @param string $field
50
+ * @return string
51
+ */
52
+ public function valueForHtmlField($field)
53
+ {
54
+ $pieces = preg_split("/[\[\]]+/", $field, 0, PREG_SPLIT_NO_EMPTY);
55
+ $params = $this->params;
56
+ foreach(array_slice($pieces, 0, -1) as $key) {
57
+ $params = $params[Braintree_Util::delimiterToCamelCase($key)];
58
+ }
59
+ $finalKey = Braintree_Util::delimiterToCamelCase(end($pieces));
60
+ $fieldValue = isset($params[$finalKey]) ? $params[$finalKey] : null;
61
+ return $fieldValue;
62
+ }
63
+
64
+ /**
65
+ * overrides default constructor
66
+ * @ignore
67
+ * @param array $response gateway response array
68
+ */
69
+ public function __construct($response)
70
+ {
71
+ $this->_attributes = $response;
72
+ $this->_set('errors', new Braintree_Error_ErrorCollection($response['errors']));
73
+
74
+ if(isset($response['verification'])) {
75
+ $this->_set('creditCardVerification', new Braintree_Result_CreditCardVerification($response['verification']));
76
+ } else {
77
+ $this->_set('creditCardVerification', null);
78
+ }
79
+
80
+ if(isset($response['transaction'])) {
81
+ $this->_set('transaction', Braintree_Transaction::factory($response['transaction']));
82
+ } else {
83
+ $this->_set('transaction', null);
84
+ }
85
+
86
+ if(isset($response['subscription'])) {
87
+ $this->_set('subscription', Braintree_Subscription::factory($response['subscription']));
88
+ } else {
89
+ $this->_set('subscription', null);
90
+ }
91
+ }
92
+
93
+ /**
94
+ * create a printable representation of the object as:
95
+ * ClassName[property=value, property=value]
96
+ * @ignore
97
+ * @return var
98
+ */
99
+ public function __toString()
100
+ {
101
+ $output = Braintree_Util::attributesToString($this->_attributes);
102
+ if (isset($this->_creditCardVerification)) {
103
+ $output .= sprintf('%s', $this->_creditCardVerification);
104
+ }
105
+ return __CLASS__ .'['.$output.']';
106
+ }
107
+ }
includes/lib/Braintree/Braintree/Result/Successful.php ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Successful Result
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Result
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Braintree Successful Result
12
+ *
13
+ * A Successful Result will be returned from gateway methods when
14
+ * validations pass. It will provide access to the created resource.
15
+ *
16
+ * For example, when creating a customer, Braintree_Result_Successful will
17
+ * respond to <b>customer</b> like so:
18
+ *
19
+ * <code>
20
+ * $result = Braintree_Customer::create(array('first_name' => "John"));
21
+ * if ($result->success) {
22
+ * // Braintree_Result_Successful
23
+ * echo "Created customer {$result->customer->id}";
24
+ * } else {
25
+ * // Braintree_Result_Error
26
+ * }
27
+ * </code>
28
+ *
29
+ *
30
+ * @package Braintree
31
+ * @subpackage Result
32
+ * @copyright 2010 Braintree Payment Solutions
33
+ */
34
+ class Braintree_Result_Successful extends Braintree_Instance
35
+ {
36
+ /**
37
+ *
38
+ * @var boolean always true
39
+ */
40
+ public $success = true;
41
+ /**
42
+ *
43
+ * @var string stores the internal name of the object providing access to
44
+ */
45
+ private $_returnObjectName;
46
+
47
+ /**
48
+ * @ignore
49
+ * @param string $classToReturn name of class to instantiate
50
+ */
51
+ public function __construct($objToReturn = null)
52
+ {
53
+ if(!empty($objToReturn)) {
54
+ // get a lowercase direct name for the property
55
+ $property = Braintree_Util::cleanClassName(
56
+ get_class($objToReturn)
57
+ );
58
+ // save the name for indirect access
59
+ $this->_returnObjectName = $property;
60
+
61
+ // create the property!
62
+ $this->$property = $objToReturn;
63
+ }
64
+ }
65
+
66
+
67
+ /**
68
+ *
69
+ * @ignore
70
+ * @return string string representation of the object's structure
71
+ */
72
+ public function __toString()
73
+ {
74
+ $returnObject = $this->_returnObjectName;
75
+ return __CLASS__ . '['.$this->$returnObject->__toString().']';
76
+ }
77
+
78
+ }
includes/lib/Braintree/Braintree/SettlementBatchSummary.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_SettlementBatchSummary extends Braintree
3
+ {
4
+ public static function generate($settlement_date, $groupByCustomField = NULL)
5
+ {
6
+ $criteria = array('settlement_date' => $settlement_date);
7
+ if (isset($groupByCustomField))
8
+ {
9
+ $criteria['group_by_custom_field'] = $groupByCustomField;
10
+ }
11
+ $params = array('settlement_batch_summary' => $criteria);
12
+ $response = Braintree_Http::post('/settlement_batch_summary', $params);
13
+
14
+ if (isset($groupByCustomField))
15
+ {
16
+ $response['settlementBatchSummary']['records'] = self::_underscoreCustomField(
17
+ $groupByCustomField,
18
+ $response['settlementBatchSummary']['records']
19
+ );
20
+ }
21
+
22
+ return self::_verifyGatewayResponse($response);
23
+ }
24
+
25
+ private static function _underscoreCustomField($groupByCustomField, $records)
26
+ {
27
+ $updatedRecords = array();
28
+
29
+ foreach ($records as $record)
30
+ {
31
+ $camelized = Braintree_Util::delimiterToCamelCase($groupByCustomField);
32
+ $record[$groupByCustomField] = $record[$camelized];
33
+ unset($record[$camelized]);
34
+ $updatedRecords[] = $record;
35
+ }
36
+
37
+ return $updatedRecords;
38
+ }
39
+
40
+ private static function _verifyGatewayResponse($response)
41
+ {
42
+ if (isset($response['settlementBatchSummary'])) {
43
+ return new Braintree_Result_Successful(
44
+ self::factory($response['settlementBatchSummary'])
45
+ );
46
+ } else if (isset($response['apiErrorResponse'])) {
47
+ return new Braintree_Result_Error($response['apiErrorResponse']);
48
+ } else {
49
+ throw new Braintree_Exception_Unexpected(
50
+ "Expected settlementBatchSummary or apiErrorResponse"
51
+ );
52
+ }
53
+ }
54
+
55
+ public static function factory($attributes)
56
+ {
57
+ $instance = new self();
58
+ $instance->_initialize($attributes);
59
+ return $instance;
60
+ }
61
+
62
+ /**
63
+ * @ignore
64
+ */
65
+ protected function _initialize($attributes)
66
+ {
67
+ $this->_attributes = $attributes;
68
+ }
69
+
70
+ public function records()
71
+ {
72
+ return $this->_attributes['records'];
73
+ }
74
+ }
includes/lib/Braintree/Braintree/Subscription.php ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Subscription module
4
+ *
5
+ * <b>== More information ==</b>
6
+ *
7
+ * For more detailed information on Subscriptions, see {@link http://www.braintreepayments.com/gateway/subscription-api http://www.braintreepaymentsolutions.com/gateway/subscription-api}
8
+ *
9
+ * PHP Version 5
10
+ *
11
+ * @package Braintree
12
+ * @copyright 2010 Braintree Payment Solutions
13
+ */
14
+ class Braintree_Subscription extends Braintree
15
+ {
16
+ const ACTIVE = 'Active';
17
+ const CANCELED = 'Canceled';
18
+ const EXPIRED = 'Expired';
19
+ const PAST_DUE = 'Past Due';
20
+ const PENDING = 'Pending';
21
+
22
+ public static function create($attributes)
23
+ {
24
+ Braintree_Util::verifyKeys(self::_createSignature(), $attributes);
25
+ $response = Braintree_Http::post('/subscriptions', array('subscription' => $attributes));
26
+ return self::_verifyGatewayResponse($response);
27
+ }
28
+
29
+ /**
30
+ * @ignore
31
+ */
32
+ public static function factory($attributes)
33
+ {
34
+ $instance = new self();
35
+ $instance->_initialize($attributes);
36
+
37
+ return $instance;
38
+ }
39
+
40
+ public static function find($id)
41
+ {
42
+ self::_validateId($id);
43
+
44
+ try {
45
+ $response = Braintree_Http::get('/subscriptions/' . $id);
46
+ return self::factory($response['subscription']);
47
+ } catch (Braintree_Exception_NotFound $e) {
48
+ throw new Braintree_Exception_NotFound('subscription with id ' . $id . ' not found');
49
+ }
50
+
51
+ }
52
+
53
+ public static function search($query)
54
+ {
55
+ $criteria = array();
56
+ foreach ($query as $term) {
57
+ $criteria[$term->name] = $term->toparam();
58
+ }
59
+
60
+
61
+ $response = braintree_http::post('/subscriptions/advanced_search_ids', array('search' => $criteria));
62
+ $pager = array(
63
+ 'className' => __CLASS__,
64
+ 'classMethod' => 'fetch',
65
+ 'methodArgs' => array($query)
66
+ );
67
+
68
+ return new Braintree_ResourceCollection($response, $pager);
69
+ }
70
+
71
+ public static function fetch($query, $ids)
72
+ {
73
+ $criteria = array();
74
+ foreach ($query as $term) {
75
+ $criteria[$term->name] = $term->toparam();
76
+ }
77
+ $criteria["ids"] = Braintree_SubscriptionSearch::ids()->in($ids)->toparam();
78
+ $response = Braintree_Http::post('/subscriptions/advanced_search', array('search' => $criteria));
79
+
80
+ return Braintree_Util::extractAttributeAsArray(
81
+ $response['subscriptions'],
82
+ 'subscription'
83
+ );
84
+ }
85
+
86
+ public static function update($subscriptionId, $attributes)
87
+ {
88
+ Braintree_Util::verifyKeys(self::_updateSignature(), $attributes);
89
+ $response = Braintree_Http::put(
90
+ '/subscriptions/' . $subscriptionId,
91
+ array('subscription' => $attributes)
92
+ );
93
+ return self::_verifyGatewayResponse($response);
94
+ }
95
+
96
+ public static function retryCharge($subscriptionId, $amount = null)
97
+ {
98
+ $transaction_params = array('type' => Braintree_Transaction::SALE,
99
+ 'subscriptionId' => $subscriptionId);
100
+ if (isset($amount)) {
101
+ $transaction_params['amount'] = $amount;
102
+ }
103
+
104
+ $response = Braintree_Http::post(
105
+ '/transactions',
106
+ array('transaction' => $transaction_params));
107
+ return self::_verifyGatewayResponse($response);
108
+ }
109
+
110
+ public static function cancel($subscriptionId)
111
+ {
112
+ $response = Braintree_Http::put('/subscriptions/' . $subscriptionId . '/cancel');
113
+ return self::_verifyGatewayResponse($response);
114
+ }
115
+
116
+ private static function _createSignature()
117
+ {
118
+ return array_merge(
119
+ array(
120
+ 'billingDayOfMonth',
121
+ 'firstBillingDate',
122
+ 'id',
123
+ 'merchantAccountId',
124
+ 'neverExpires',
125
+ 'numberOfBillingCycles',
126
+ 'paymentMethodToken',
127
+ 'planId',
128
+ 'price',
129
+ 'trialDuration',
130
+ 'trialDurationUnit',
131
+ 'trialPeriod',
132
+ array('descriptor' => array('name', 'phone')),
133
+ array('options' => array('doNotInheritAddOnsOrDiscounts', 'startImmediately')),
134
+ ),
135
+ self::_addOnDiscountSignature()
136
+ );
137
+ }
138
+
139
+ private static function _updateSignature()
140
+ {
141
+ return array_merge(
142
+ array(
143
+ 'merchantAccountId', 'numberOfBillingCycles', 'paymentMethodToken', 'planId',
144
+ 'id', 'neverExpires', 'price',
145
+ array('descriptor' => array('name', 'phone')),
146
+ array('options' => array('prorateCharges', 'replaceAllAddOnsAndDiscounts', 'revertSubscriptionOnProrationFailure')),
147
+ ),
148
+ self::_addOnDiscountSignature()
149
+ );
150
+ }
151
+
152
+ private static function _addOnDiscountSignature()
153
+ {
154
+ return array(
155
+ array(
156
+ 'addOns' => array(
157
+ array('add' => array('amount', 'inheritedFromId', 'neverExpires', 'numberOfBillingCycles', 'quantity')),
158
+ array('update' => array('amount', 'existingId', 'neverExpires', 'numberOfBillingCycles', 'quantity')),
159
+ array('remove' => array('_anyKey_')),
160
+ )
161
+ ),
162
+ array(
163
+ 'discounts' => array(
164
+ array('add' => array('amount', 'inheritedFromId', 'neverExpires', 'numberOfBillingCycles', 'quantity')),
165
+ array('update' => array('amount', 'existingId', 'neverExpires', 'numberOfBillingCycles', 'quantity')),
166
+ array('remove' => array('_anyKey_')),
167
+ )
168
+ )
169
+ );
170
+ }
171
+
172
+ /**
173
+ * @ignore
174
+ */
175
+ protected function _initialize($attributes)
176
+ {
177
+ $this->_attributes = $attributes;
178
+
179
+ $addOnArray = array();
180
+ if (isset($attributes['addOns'])) {
181
+ foreach ($attributes['addOns'] AS $addOn) {
182
+ $addOnArray[] = Braintree_AddOn::factory($addOn);
183
+ }
184
+ }
185
+ $this->_attributes['addOns'] = $addOnArray;
186
+
187
+ $discountArray = array();
188
+ if (isset($attributes['discounts'])) {
189
+ foreach ($attributes['discounts'] AS $discount) {
190
+ $discountArray[] = Braintree_Discount::factory($discount);
191
+ }
192
+ }
193
+ $this->_attributes['discounts'] = $discountArray;
194
+
195
+ if (isset($attributes['descriptor'])) {
196
+ $this->_set('descriptor', new Braintree_Descriptor($attributes['descriptor']));
197
+ }
198
+
199
+ $transactionArray = array();
200
+ if (isset($attributes['transactions'])) {
201
+ foreach ($attributes['transactions'] AS $transaction) {
202
+ $transactionArray[] = Braintree_Transaction::factory($transaction);
203
+ }
204
+ }
205
+ $this->_attributes['transactions'] = $transactionArray;
206
+ }
207
+
208
+ /**
209
+ * @ignore
210
+ */
211
+ private static function _validateId($id = null) {
212
+ if (empty($id)) {
213
+ throw new InvalidArgumentException(
214
+ 'expected subscription id to be set'
215
+ );
216
+ }
217
+ if (!preg_match('/^[0-9A-Za-z_-]+$/', $id)) {
218
+ throw new InvalidArgumentException(
219
+ $id . ' is an invalid subscription id.'
220
+ );
221
+ }
222
+ }
223
+ /**
224
+ * @ignore
225
+ */
226
+ private static function _verifyGatewayResponse($response)
227
+ {
228
+ if (isset($response['subscription'])) {
229
+ return new Braintree_Result_Successful(
230
+ self::factory($response['subscription'])
231
+ );
232
+ } else if (isset($response['transaction'])) {
233
+ // return a populated instance of Braintree_Transaction, for subscription retryCharge
234
+ return new Braintree_Result_Successful(
235
+ Braintree_Transaction::factory($response['transaction'])
236
+ );
237
+ } else if (isset($response['apiErrorResponse'])) {
238
+ return new Braintree_Result_Error($response['apiErrorResponse']);
239
+ } else {
240
+ throw new Braintree_Exception_Unexpected(
241
+ "Expected subscription, transaction, or apiErrorResponse"
242
+ );
243
+ }
244
+ }
245
+
246
+ /**
247
+ * returns a string representation of the customer
248
+ * @return string
249
+ */
250
+ public function __toString()
251
+ {
252
+ return __CLASS__ . '[' .
253
+ Braintree_Util::attributesToString($this->_attributes) .']';
254
+ }
255
+
256
+ }
includes/lib/Braintree/Braintree/SubscriptionSearch.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_SubscriptionSearch
3
+ {
4
+ static function billingCyclesRemaining()
5
+ {
6
+ return new Braintree_RangeNode('billing_cycles_remaining');
7
+ }
8
+
9
+ static function daysPastDue()
10
+ {
11
+ return new Braintree_RangeNode('days_past_due');
12
+ }
13
+
14
+ static function id()
15
+ {
16
+ return new Braintree_TextNode('id');
17
+ }
18
+
19
+ static function inTrialPeriod()
20
+ {
21
+ return new Braintree_MultipleValueNode('in_trial_period', array(true, false));
22
+ }
23
+
24
+ static function merchantAccountId()
25
+ {
26
+ return new Braintree_MultipleValueNode('merchant_account_id');
27
+ }
28
+
29
+ static function nextBillingDate()
30
+ {
31
+ return new Braintree_RangeNode('next_billing_date');
32
+ }
33
+
34
+ static function planId()
35
+ {
36
+ return new Braintree_MultipleValueOrTextNode('plan_id');
37
+ }
38
+
39
+ static function price()
40
+ {
41
+ return new Braintree_RangeNode('price');
42
+ }
43
+
44
+ static function status()
45
+ {
46
+ return new Braintree_MultipleValueNode("status", array(
47
+ Braintree_Subscription::ACTIVE,
48
+ Braintree_Subscription::CANCELED,
49
+ Braintree_Subscription::EXPIRED,
50
+ Braintree_Subscription::PAST_DUE,
51
+ Braintree_Subscription::PENDING
52
+ ));
53
+ }
54
+
55
+ static function transactionId()
56
+ {
57
+ return new Braintree_TextNode('transaction_id');
58
+ }
59
+
60
+ static function ids()
61
+ {
62
+ return new Braintree_MultipleValueNode('ids');
63
+ }
64
+ }
includes/lib/Braintree/Braintree/SubscriptionStatus.php ADDED
File without changes
includes/lib/Braintree/Braintree/Test/CreditCardNumbers.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Credit card information used for testing purposes
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Test
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Credit card information used for testing purposes
12
+ *
13
+ * The constants contained in the Braintree_Test_CreditCardNumbers class provide
14
+ * credit card numbers that should be used when working in the sandbox environment.
15
+ * The sandbox will not accept any credit card numbers other than the ones listed below.
16
+ *
17
+ * @package Braintree
18
+ * @subpackage Test
19
+ * @copyright 2010 Braintree Payment Solutions
20
+ */
21
+ class Braintree_Test_CreditCardNumbers
22
+ {
23
+ public static $amExes = array(
24
+ '378282246310005',
25
+ '371449635398431',
26
+ '378734493671000',
27
+ );
28
+ public static $carteBlanches = array('30569309025904',);
29
+ public static $dinersClubs = array('38520000023237',);
30
+ public static $discoverCards = array(
31
+ '6011111111111117',
32
+ '6011000990139424',
33
+ );
34
+ public static $JCBs = array(
35
+ '3530111333300000',
36
+ '3566002020360505',
37
+ );
38
+
39
+ public static $masterCard = '5555555555554444';
40
+ public static $masterCardInternational = '5105105105105100';
41
+ public static $masterCards = array(
42
+ '5105105105105100',
43
+ '5555555555554444',
44
+ );
45
+
46
+ public static $visa = '4012888888881881';
47
+ public static $visaInternational = '4009348888881881';
48
+ public static $visas = array(
49
+ '4009348888881881',
50
+ '4012888888881881',
51
+ '4111111111111111',
52
+ '4000111111111115',
53
+ );
54
+
55
+ public static $unknowns = array(
56
+ '1000000000000008',
57
+ );
58
+
59
+ public static $failsSandboxVerification = array(
60
+ 'AmEx' => '378734493671000',
61
+ 'Discover' => '6011000990139424',
62
+ 'MasterCard' => '5105105105105100',
63
+ 'Visa' => '4000111111111115',
64
+ );
65
+
66
+
67
+ public static function getAll()
68
+ {
69
+ return array_merge(
70
+ self::$amExes,
71
+ self::$discoverCards,
72
+ self::$masterCards,
73
+ self::$visas
74
+ );
75
+ }
76
+ }
includes/lib/Braintree/Braintree/Test/TransactionAmounts.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Transaction amounts used for testing purposes
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Test
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Transaction amounts used for testing purposes
12
+ *
13
+ * The constants in this class can be used to create transactions with
14
+ * the desired status in the sandbox environment.
15
+ *
16
+ * @package Braintree
17
+ * @subpackage Test
18
+ * @copyright 2010 Braintree Payment Solutions
19
+ */
20
+ class Braintree_Test_TransactionAmounts
21
+ {
22
+ public static $authorize = '1000.00';
23
+ public static $decline = '2000.00';
24
+ }
includes/lib/Braintree/Braintree/TextNode.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Braintree_TextNode extends Braintree_PartialMatchNode
4
+ {
5
+ function contains($value)
6
+ {
7
+ $this->searchTerms["contains"] = strval($value);
8
+ return $this;
9
+ }
10
+ }
includes/lib/Braintree/Braintree/Transaction.php ADDED
@@ -0,0 +1,664 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Transaction processor
4
+ *
5
+ * @package Braintree
6
+ * @category Resources
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Creates and manages transactions
12
+ *
13
+ * At minimum, an amount, credit card number, and
14
+ * credit card expiration date are required.
15
+ *
16
+ * <b>Minimalistic example:</b>
17
+ * <code>
18
+ * Braintree_Transaction::saleNoValidate(array(
19
+ * 'amount' => '100.00',
20
+ * 'creditCard' => array(
21
+ * 'number' => '5105105105105100',
22
+ * 'expirationDate' => '05/12',
23
+ * ),
24
+ * ));
25
+ * </code>
26
+ *
27
+ * <b>Full example:</b>
28
+ * <code>
29
+ * Braintree_Transaction::saleNoValidate(array(
30
+ * 'amount' => '100.00',
31
+ * 'orderId' => '123',
32
+ * 'channel' => 'MyShoppingCardProvider',
33
+ * 'creditCard' => array(
34
+ * // if token is omitted, the gateway will generate a token
35
+ * 'token' => 'credit_card_123',
36
+ * 'number' => '5105105105105100',
37
+ * 'expirationDate' => '05/2011',
38
+ * 'cvv' => '123',
39
+ * ),
40
+ * 'customer' => array(
41
+ * // if id is omitted, the gateway will generate an id
42
+ * 'id' => 'customer_123',
43
+ * 'firstName' => 'Dan',
44
+ * 'lastName' => 'Smith',
45
+ * 'company' => 'Braintree Payment Solutions',
46
+ * 'email' => 'dan@example.com',
47
+ * 'phone' => '419-555-1234',
48
+ * 'fax' => '419-555-1235',
49
+ * 'website' => 'http://braintreepayments.com'
50
+ * ),
51
+ * 'billing' => array(
52
+ * 'firstName' => 'Carl',
53
+ * 'lastName' => 'Jones',
54
+ * 'company' => 'Braintree',
55
+ * 'streetAddress' => '123 E Main St',
56
+ * 'extendedAddress' => 'Suite 403',
57
+ * 'locality' => 'Chicago',
58
+ * 'region' => 'IL',
59
+ * 'postalCode' => '60622',
60
+ * 'countryName' => 'United States of America'
61
+ * ),
62
+ * 'shipping' => array(
63
+ * 'firstName' => 'Andrew',
64
+ * 'lastName' => 'Mason',
65
+ * 'company' => 'Braintree',
66
+ * 'streetAddress' => '456 W Main St',
67
+ * 'extendedAddress' => 'Apt 2F',
68
+ * 'locality' => 'Bartlett',
69
+ * 'region' => 'IL',
70
+ * 'postalCode' => '60103',
71
+ * 'countryName' => 'United States of America'
72
+ * ),
73
+ * 'customFields' => array(
74
+ * 'birthdate' => '11/13/1954'
75
+ * )
76
+ * )
77
+ * </code>
78
+ *
79
+ * <b>== Storing in the Vault ==</b>
80
+ *
81
+ * The customer and credit card information used for
82
+ * a transaction can be stored in the vault by setting
83
+ * <i>transaction[options][storeInVault]</i> to true.
84
+ * <code>
85
+ * $transaction = Braintree_Transaction::saleNoValidate(array(
86
+ * 'customer' => array(
87
+ * 'firstName' => 'Adam',
88
+ * 'lastName' => 'Williams'
89
+ * ),
90
+ * 'creditCard' => array(
91
+ * 'number' => '5105105105105100',
92
+ * 'expirationDate' => '05/2012'
93
+ * ),
94
+ * 'options' => array(
95
+ * 'storeInVault' => true
96
+ * )
97
+ * ));
98
+ *
99
+ * echo $transaction->customerDetails->id
100
+ * // '865534'
101
+ * echo $transaction->creditCardDetails->token
102
+ * // '6b6m'
103
+ * </code>
104
+ *
105
+ * To also store the billing address in the vault, pass the
106
+ * <b>addBillingAddressToPaymentMethod</b> option.
107
+ * <code>
108
+ * Braintree_Transaction.saleNoValidate(array(
109
+ * ...
110
+ * 'options' => array(
111
+ * 'storeInVault' => true
112
+ * 'addBillingAddressToPaymentMethod' => true
113
+ * )
114
+ * ));
115
+ * </code>
116
+ *
117
+ * <b>== Submitting for Settlement==</b>
118
+ *
119
+ * This can only be done when the transction's
120
+ * status is <b>authorized</b>. If <b>amount</b> is not specified,
121
+ * the full authorized amount will be settled. If you would like to settle
122
+ * less than the full authorized amount, pass the desired amount.
123
+ * You cannot settle more than the authorized amount.
124
+ *
125
+ * A transaction can be submitted for settlement when created by setting
126
+ * $transaction[options][submitForSettlement] to true.
127
+ *
128
+ * <code>
129
+ * $transaction = Braintree_Transaction::saleNoValidate(array(
130
+ * 'amount' => '100.00',
131
+ * 'creditCard' => array(
132
+ * 'number' => '5105105105105100',
133
+ * 'expirationDate' => '05/2012'
134
+ * ),
135
+ * 'options' => array(
136
+ * 'submitForSettlement' => true
137
+ * )
138
+ * ));
139
+ * </code>
140
+ *
141
+ * <b>== More information ==</b>
142
+ *
143
+ * For more detailed information on Transactions, see {@link http://www.braintreepayments.com/gateway/transaction-api http://www.braintreepaymentsolutions.com/gateway/transaction-api}
144
+ *
145
+ * @package Braintree
146
+ * @category Resources
147
+ * @copyright 2010 Braintree Payment Solutions
148
+ *
149
+ *
150
+ * @property-read string $avsErrorResponseCode
151
+ * @property-read string $avsPostalCodeResponseCode
152
+ * @property-read string $avsStreetAddressResponseCode
153
+ * @property-read string $cvvResponseCode
154
+ * @property-read string $id transaction id
155
+ * @property-read string $amount transaction amount
156
+ * @property-read object $billingDetails transaction billing address
157
+ * @property-read string $createdAt transaction created timestamp
158
+ * @property-read object $creditCardDetails transaction credit card info
159
+ * @property-read object $customerDetails transaction customer info
160
+ * @property-read array $customFields custom fields passed with the request
161
+ * @property-read string $processorResponseCode gateway response code
162
+ * @property-read object $shippingDetails transaction shipping address
163
+ * @property-read string $status transaction status
164
+ * @property-read array $statusHistory array of StatusDetails objects
165
+ * @property-read string $type transaction type
166
+ * @property-read string $updatedAt transaction updated timestamp
167
+ *
168
+ */
169
+
170
+ final class Braintree_Transaction extends Braintree
171
+ {
172
+ // Transaction Status
173
+ const AUTHORIZATION_EXPIRED = 'authorization_expired';
174
+ const AUTHORIZING = 'authorizing';
175
+ const AUTHORIZED = 'authorized';
176
+ const GATEWAY_REJECTED = 'gateway_rejected';
177
+ const FAILED = 'failed';
178
+ const PROCESSOR_DECLINED = 'processor_declined';
179
+ const SETTLED = 'settled';
180
+ const SETTLING = 'settling';
181
+ const SUBMITTED_FOR_SETTLEMENT = 'submitted_for_settlement';
182
+ const VOIDED = 'voided';
183
+
184
+ // Transaction Types
185
+ const SALE = 'sale';
186
+ const CREDIT = 'credit';
187
+
188
+ // Transaction Created Using
189
+ const FULL_INFORMATION = 'full_information';
190
+ const TOKEN = 'token';
191
+
192
+ // Transaction Sources
193
+ const API = 'api';
194
+ const CONTROL_PANEL = 'control_panel';
195
+ const RECURRING = 'recurring';
196
+
197
+ // Gateway Rejection Reason
198
+ const AVS = 'avs';
199
+ const AVS_AND_CVV = 'avs_and_cvv';
200
+ const CVV = 'cvv';
201
+ const DUPLICATE = 'duplicate';
202
+
203
+ public static function cloneTransaction($transactionId, $attribs)
204
+ {
205
+ Braintree_Util::verifyKeys(self::cloneSignature(), $attribs);
206
+ return self::_doCreate('/transactions/' . $transactionId . '/clone', array('transactionClone' => $attribs));
207
+ }
208
+
209
+ /**
210
+ * @ignore
211
+ * @access public
212
+ * @param array $attribs
213
+ * @return object
214
+ */
215
+ private static function create($attribs)
216
+ {
217
+ Braintree_Util::verifyKeys(self::createSignature(), $attribs);
218
+ return self::_doCreate('/transactions', array('transaction' => $attribs));
219
+ }
220
+
221
+ /**
222
+ *
223
+ * @ignore
224
+ * @access public
225
+ * @param array $attribs
226
+ * @return object
227
+ * @throws Braintree_Exception_ValidationError
228
+ */
229
+ private static function createNoValidate($attribs)
230
+ {
231
+ $result = self::create($attribs);
232
+ return self::returnObjectOrThrowException(__CLASS__, $result);
233
+ }
234
+ /**
235
+ *
236
+ * @access public
237
+ * @param array $attribs
238
+ * @return object
239
+ */
240
+ public static function createFromTransparentRedirect($queryString)
241
+ {
242
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::confirm", E_USER_NOTICE);
243
+ $params = Braintree_TransparentRedirect::parseAndValidateQueryString(
244
+ $queryString
245
+ );
246
+ return self::_doCreate(
247
+ '/transactions/all/confirm_transparent_redirect_request',
248
+ array('id' => $params['id'])
249
+ );
250
+ }
251
+ /**
252
+ *
253
+ * @access public
254
+ * @param none
255
+ * @return string
256
+ */
257
+ public static function createTransactionUrl()
258
+ {
259
+ trigger_error("DEPRECATED: Please use Braintree_TransparentRedirectRequest::url", E_USER_NOTICE);
260
+ return Braintree_Configuration::merchantUrl() .
261
+ '/transactions/all/create_via_transparent_redirect_request';
262
+ }
263
+
264
+ public static function cloneSignature()
265
+ {
266
+ return array('amount', 'channel', array('options' => array('submitForSettlement')));
267
+ }
268
+
269
+ /**
270
+ * creates a full array signature of a valid gateway request
271
+ * @return array gateway request signature format
272
+ */
273
+ public static function createSignature()
274
+ {
275
+ return array(
276
+ 'amount', 'customerId', 'merchantAccountId', 'orderId', 'channel', 'paymentMethodToken',
277
+ 'purchaseOrderNumber', 'recurring', 'shippingAddressId', 'taxAmount', 'taxExempt', 'type', 'venmoSdkPaymentMethodCode',
278
+ array('creditCard' =>
279
+ array('token', 'cardholderName', 'cvv', 'expirationDate', 'expirationMonth', 'expirationYear', 'number'),
280
+ ),
281
+ array('customer' =>
282
+ array(
283
+ 'id', 'company', 'email', 'fax', 'firstName',
284
+ 'lastName', 'phone', 'website'),
285
+ ),
286
+ array('billing' =>
287
+ array(
288
+ 'firstName', 'lastName', 'company', 'countryName',
289
+ 'countryCodeAlpha2', 'countryCodeAlpha3', 'countryCodeNumeric',
290
+ 'extendedAddress', 'locality', 'postalCode', 'region',
291
+ 'streetAddress'),
292
+ ),
293
+ array('shipping' =>
294
+ array(
295
+ 'firstName', 'lastName', 'company', 'countryName',
296
+ 'countryCodeAlpha2', 'countryCodeAlpha3', 'countryCodeNumeric',
297
+ 'extendedAddress', 'locality', 'postalCode', 'region',
298
+ 'streetAddress'),
299
+ ),
300
+ array('options' =>
301
+ array(
302
+ 'storeInVault',
303
+ 'storeInVaultOnSuccess',
304
+ 'submitForSettlement',
305
+ 'addBillingAddressToPaymentMethod',
306
+ 'venmoSdkSession',
307
+ 'storeShippingAddressInVault'),
308
+ ),
309
+ array('customFields' => array('_anyKey_')
310
+ ),
311
+ array('descriptor' => array('name', 'phone')),
312
+ );
313
+ }
314
+
315
+ /**
316
+ *
317
+ * @access public
318
+ * @param array $attribs
319
+ * @return object
320
+ */
321
+ public static function credit($attribs)
322
+ {
323
+ return self::create(array_merge($attribs, array('type' => Braintree_Transaction::CREDIT)));
324
+ }
325
+
326
+ /**
327
+ *
328
+ * @access public
329
+ * @param array $attribs
330
+ * @return object
331
+ * @throws Braintree_Exception_ValidationError
332
+ */
333
+ public static function creditNoValidate($attribs)
334
+ {
335
+ $result = self::credit($attribs);
336
+ return self::returnObjectOrThrowException(__CLASS__, $result);
337
+ }
338
+
339
+
340
+ /**
341
+ * @access public
342
+ *
343
+ */
344
+ public static function find($id)
345
+ {
346
+ self::_validateId($id);
347
+ try {
348
+ $response = Braintree_Http::get('/transactions/'.$id);
349
+ return self::factory($response['transaction']);
350
+ } catch (Braintree_Exception_NotFound $e) {
351
+ throw new Braintree_Exception_NotFound(
352
+ 'transaction with id ' . $id . ' not found'
353
+ );
354
+ }
355
+
356
+ }
357
+ /**
358
+ * new sale
359
+ * @param array $attribs
360
+ * @return array
361
+ */
362
+ public static function sale($attribs)
363
+ {
364
+ return self::create(array_merge(array('type' => Braintree_Transaction::SALE), $attribs));
365
+ }
366
+
367
+ /**
368
+ * roughly equivalent to the ruby bang method
369
+ * @access public
370
+ * @param array $attribs
371
+ * @return array
372
+ * @throws Braintree_Exception_ValidationsFailed
373
+ */
374
+ public static function saleNoValidate($attribs)
375
+ {
376
+ $result = self::sale($attribs);
377
+ return self::returnObjectOrThrowException(__CLASS__, $result);
378
+ }
379
+
380
+ /**
381
+ * Returns a ResourceCollection of transactions matching the search query.
382
+ *
383
+ * If <b>query</b> is a string, the search will be a basic search.
384
+ * If <b>query</b> is a hash, the search will be an advanced search.
385
+ * For more detailed information and examples, see {@link http://www.braintreepayments.com/gateway/transaction-api#searching http://www.braintreepaymentsolutions.com/gateway/transaction-api}
386
+ *
387
+ * @param mixed $query search query
388
+ * @param array $options options such as page number
389
+ * @return object Braintree_ResourceCollection
390
+ * @throws InvalidArgumentException
391
+ */
392
+ public static function search($query)
393
+ {
394
+ $criteria = array();
395
+ foreach ($query as $term) {
396
+ $criteria[$term->name] = $term->toparam();
397
+ }
398
+
399
+ $response = braintree_http::post('/transactions/advanced_search_ids', array('search' => $criteria));
400
+ $pager = array(
401
+ 'className' => __CLASS__,
402
+ 'classMethod' => 'fetch',
403
+ 'methodArgs' => array($query)
404
+ );
405
+
406
+ return new Braintree_ResourceCollection($response, $pager);
407
+ }
408
+
409
+ public static function fetch($query, $ids)
410
+ {
411
+ $criteria = array();
412
+ foreach ($query as $term) {
413
+ $criteria[$term->name] = $term->toparam();
414
+ }
415
+ $criteria["ids"] = Braintree_TransactionSearch::ids()->in($ids)->toparam();
416
+ $response = braintree_http::post('/transactions/advanced_search', array('search' => $criteria));
417
+
418
+ return braintree_util::extractattributeasarray(
419
+ $response['creditCardTransactions'],
420
+ 'transaction'
421
+ );
422
+ }
423
+
424
+ /**
425
+ * void a transaction by id
426
+ *
427
+ * @param string $id transaction id
428
+ * @return object Braintree_Result_Successful|Braintree_Result_Error
429
+ */
430
+ public static function void($transactionId)
431
+ {
432
+ self::_validateId($transactionId);
433
+
434
+ $response = Braintree_Http::put('/transactions/'. $transactionId . '/void');
435
+ return self::_verifyGatewayResponse($response);
436
+ }
437
+ /**
438
+ *
439
+ */
440
+ public static function voidNoValidate($transactionId)
441
+ {
442
+ $result = self::void($transactionId);
443
+ return self::returnObjectOrThrowException(__CLASS__, $result);
444
+ }
445
+
446
+ public static function submitForSettlement($transactionId, $amount = null)
447
+ {
448
+ self::_validateId($transactionId);
449
+
450
+ $response = Braintree_Http::put(
451
+ '/transactions/'. $transactionId . '/submit_for_settlement',
452
+ array( 'transaction' => array( 'amount' => $amount))
453
+ );
454
+ return self::_verifyGatewayResponse($response);
455
+ }
456
+
457
+ public static function submitForSettlementNoValidate($transactionId, $amount = null)
458
+ {
459
+ $result = self::submitForSettlement($transactionId, $amount);
460
+ return self::returnObjectOrThrowException(__CLASS__, $result);
461
+ }
462
+
463
+
464
+ /**
465
+ * sets instance properties from an array of values
466
+ *
467
+ * @ignore
468
+ * @access protected
469
+ * @param array $transactionAttribs array of transaction data
470
+ * @return none
471
+ */
472
+ protected function _initialize($transactionAttribs)
473
+ {
474
+ $this->_attributes = $transactionAttribs;
475
+
476
+ $this->_set('creditCardDetails',
477
+ new Braintree_Transaction_CreditCardDetails(
478
+ $transactionAttribs['creditCard']
479
+ )
480
+ );
481
+ $this->_set('customerDetails',
482
+ new Braintree_Transaction_CustomerDetails(
483
+ $transactionAttribs['customer']
484
+ )
485
+ );
486
+ $this->_set('billingDetails',
487
+ new Braintree_Transaction_AddressDetails(
488
+ $transactionAttribs['billing']
489
+ )
490
+ );
491
+ $this->_set('shippingDetails',
492
+ new Braintree_Transaction_AddressDetails(
493
+ $transactionAttribs['shipping']
494
+ )
495
+ );
496
+ $this->_set('subscriptionDetails',
497
+ new Braintree_Transaction_SubscriptionDetails(
498
+ $transactionAttribs['subscription']
499
+ )
500
+ );
501
+ $this->_set('descriptor',
502
+ new Braintree_Descriptor(
503
+ $transactionAttribs['descriptor']
504
+ )
505
+ );
506
+
507
+ $statusHistory = array();
508
+ foreach ($transactionAttribs['statusHistory'] AS $history) {
509
+ $statusHistory[] = new Braintree_Transaction_StatusDetails($history);
510
+ }
511
+ $this->_set('statusHistory', $statusHistory);
512
+
513
+
514
+ $addOnArray = array();
515
+ if (isset($transactionAttribs['addOns'])) {
516
+ foreach ($transactionAttribs['addOns'] AS $addOn) {
517
+ $addOnArray[] = Braintree_AddOn::factory($addOn);
518
+ }
519
+ }
520
+ $this->_set('addOns', $addOnArray);
521
+
522
+ $discountArray = array();
523
+ if (isset($transactionAttribs['discounts'])) {
524
+ foreach ($transactionAttribs['discounts'] AS $discount) {
525
+ $discountArray[] = Braintree_Discount::factory($discount);
526
+ }
527
+ }
528
+ $this->_set('discounts', $discountArray);
529
+ }
530
+
531
+ /**
532
+ * returns a string representation of the transaction
533
+ * @return string
534
+ */
535
+ public function __toString()
536
+ {
537
+ // array of attributes to print
538
+ $display = array(
539
+ 'id', 'type', 'amount', 'status',
540
+ 'createdAt', 'creditCardDetails', 'customerDetails'
541
+ );
542
+
543
+ $displayAttributes = array();
544
+ foreach ($display AS $attrib) {
545
+ $displayAttributes[$attrib] = $this->$attrib;
546
+ }
547
+ return __CLASS__ . '[' .
548
+ Braintree_Util::attributesToString($displayAttributes) .']';
549
+ }
550
+
551
+ public static function refund($transactionId, $amount = null)
552
+ {
553
+ $params = array('transaction' => array('amount' => $amount));
554
+ $response = Braintree_Http::post('/transactions/' . $transactionId . '/refund', $params);
555
+ return self::_verifyGatewayResponse($response);
556
+ }
557
+
558
+ public function isEqual($otherTx)
559
+ {
560
+ return $this->id === $otherTx->id;
561
+ }
562
+
563
+ public function vaultCreditCard()
564
+ {
565
+ $token = $this->creditCardDetails->token;
566
+ if (empty($token)) {
567
+ return null;
568
+ }
569
+ else {
570
+ return Braintree_CreditCard::find($token);
571
+ }
572
+ }
573
+
574
+ public function vaultCustomer()
575
+ {
576
+ $customerId = $this->customerDetails->id;
577
+ if (empty($customerId)) {
578
+ return null;
579
+ }
580
+ else {
581
+ return Braintree_Customer::find($customerId);
582
+ }
583
+ }
584
+
585
+ /**
586
+ * sends the create request to the gateway
587
+ *
588
+ * @ignore
589
+ * @param var $url
590
+ * @param array $params
591
+ * @return mixed
592
+ */
593
+ public static function _doCreate($url, $params)
594
+ {
595
+ $response = Braintree_Http::post($url, $params);
596
+
597
+ return self::_verifyGatewayResponse($response);
598
+ }
599
+
600
+ /**
601
+ * verifies that a valid transaction id is being used
602
+ * @ignore
603
+ * @param string transaction id
604
+ * @throws InvalidArgumentException
605
+ */
606
+ private static function _validateId($id = null) {
607
+ if (empty($id)) {
608
+ throw new InvalidArgumentException(
609
+ 'expected transaction id to be set'
610
+ );
611
+ }
612
+ if (!preg_match('/^[0-9a-z]+$/', $id)) {
613
+ throw new InvalidArgumentException(
614
+ $id . ' is an invalid transaction id.'
615
+ );
616
+ }
617
+ }
618
+
619
+
620
+ /* private class methods */
621
+
622
+ /**
623
+ * generic method for validating incoming gateway responses
624
+ *
625
+ * creates a new Braintree_Transaction object and encapsulates
626
+ * it inside a Braintree_Result_Successful object, or
627
+ * encapsulates a Braintree_Errors object inside a Result_Error
628
+ * alternatively, throws an Unexpected exception if the response is invalid.
629
+ *
630
+ * @ignore
631
+ * @param array $response gateway response values
632
+ * @return object Result_Successful or Result_Error
633
+ * @throws Braintree_Exception_Unexpected
634
+ */
635
+ private static function _verifyGatewayResponse($response)
636
+ {
637
+ if (isset($response['transaction'])) {
638
+ // return a populated instance of Braintree_Transaction
639
+ return new Braintree_Result_Successful(
640
+ self::factory($response['transaction'])
641
+ );
642
+ } else if (isset($response['apiErrorResponse'])) {
643
+ return new Braintree_Result_Error($response['apiErrorResponse']);
644
+ } else {
645
+ throw new Braintree_Exception_Unexpected(
646
+ "Expected transaction or apiErrorResponse"
647
+ );
648
+ }
649
+ }
650
+
651
+ /**
652
+ * factory method: returns an instance of Braintree_Transaction
653
+ * to the requesting method, with populated properties
654
+ *
655
+ * @ignore
656
+ * @return object instance of Braintree_Transaction
657
+ */
658
+ public static function factory($attributes)
659
+ {
660
+ $instance = new self();
661
+ $instance->_initialize($attributes);
662
+ return $instance;
663
+ }
664
+ }
includes/lib/Braintree/Braintree/Transaction/AddressDetails.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Address details from a transaction
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Transaction
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Creates an instance of AddressDetails as returned from a transaction
12
+ *
13
+ *
14
+ * @package Braintree
15
+ * @subpackage Transaction
16
+ * @copyright 2010 Braintree Payment Solutions
17
+ *
18
+ * @property-read string $firstName
19
+ * @property-read string $lastName
20
+ * @property-read string $company
21
+ * @property-read string $streetAddress
22
+ * @property-read string $extendedAddress
23
+ * @property-read string $locality
24
+ * @property-read string $region
25
+ * @property-read string $postalCode
26
+ * @property-read string $countryName
27
+ * @uses Braintree_Instance inherits methods
28
+ */
29
+ class Braintree_Transaction_AddressDetails extends Braintree_Instance
30
+ {
31
+ protected $_attributes = array();
32
+ }
includes/lib/Braintree/Braintree/Transaction/CreditCardDetails.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * CreditCard details from a transaction
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Transaction
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * creates an instance of CreditCardDetails
12
+ *
13
+ *
14
+ * @package Braintree
15
+ * @subpackage Transaction
16
+ * @copyright 2010 Braintree Payment Solutions
17
+ *
18
+ * @property-read string $bin
19
+ * @property-read string $cardType
20
+ * @property-read string $expirationDate
21
+ * @property-read string $expirationMonth
22
+ * @property-read string $expirationYear
23
+ * @property-read string $issuerLocation
24
+ * @property-read string $last4
25
+ * @property-read string $maskedNumber
26
+ * @property-read string $token
27
+ * @uses Braintree_Instance inherits methods
28
+ */
29
+ class Braintree_Transaction_CreditCardDetails extends Braintree_Instance
30
+ {
31
+ protected $_attributes = array();
32
+
33
+ /**
34
+ * @ignore
35
+ */
36
+ public function __construct($attributes)
37
+ {
38
+ parent::__construct($attributes);
39
+ $this->_attributes['expirationDate'] = $this->expirationMonth . '/' . $this->expirationYear;
40
+ $this->_attributes['maskedNumber'] = $this->bin . '******' . $this->last4;
41
+
42
+ }
43
+ }
includes/lib/Braintree/Braintree/Transaction/CustomerDetails.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Customer details from a transaction
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Transaction
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Creates an instance of customer details as returned from a transaction
12
+ *
13
+ * @package Braintree
14
+ * @subpackage Transaction
15
+ * @copyright 2010 Braintree Payment Solutions
16
+ *
17
+ * @property-read string $company
18
+ * @property-read string $email
19
+ * @property-read string $fax
20
+ * @property-read string $firstName
21
+ * @property-read string $id
22
+ * @property-read string $lastName
23
+ * @property-read string $phone
24
+ * @property-read string $website
25
+ * @uses Braintree_Instance inherits methods
26
+ */
27
+ class Braintree_Transaction_CustomerDetails extends Braintree_Instance
28
+ {
29
+ }
includes/lib/Braintree/Braintree/Transaction/StatusDetails.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Status details from a transaction
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Transaction
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Creates an instance of StatusDetails, as part of a transaction response
12
+ *
13
+ * @package Braintree
14
+ * @copyright 2010 Braintree Payment Solutions
15
+ *
16
+ * @property-read string $amount
17
+ * @property-read string $status
18
+ * @property-read string $timestamp
19
+ * @property-read string $transactionSource
20
+ * @property-read string $user
21
+ * @uses Braintree_Instance inherits methods
22
+ */
23
+ class Braintree_Transaction_StatusDetails extends Braintree_Instance
24
+ {
25
+ }
includes/lib/Braintree/Braintree/Transaction/SubscriptionDetails.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Customer details from a transaction
4
+ *
5
+ * @package Braintree
6
+ * @subpackage Transaction
7
+ * @copyright 2010 Braintree Payment Solutions
8
+ */
9
+
10
+ /**
11
+ * Creates an instance of customer details as returned from a transaction
12
+ *
13
+ * @package Braintree
14
+ * @subpackage Transaction
15
+ * @copyright 2010 Braintree Payment Solutions
16
+ *
17
+ * @property-read string $billing_period_start_date
18
+ * @property-read string $billing_period_end_date
19
+ */
20
+ class Braintree_Transaction_SubscriptionDetails extends Braintree_Instance
21
+ {
22
+ }
includes/lib/Braintree/Braintree/TransactionSearch.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_TransactionSearch
3
+ {
4
+ static function billingCompany() { return new Braintree_TextNode('billing_company'); }
5
+ static function billingCountryName() { return new Braintree_TextNode('billing_country_name'); }
6
+ static function billingExtendedAddress() { return new Braintree_TextNode('billing_extended_address'); }
7
+ static function billingFirstName() { return new Braintree_TextNode('billing_first_name'); }
8
+ static function billingLastName() { return new Braintree_TextNode('billing_last_name'); }
9
+ static function billingLocality() { return new Braintree_TextNode('billing_locality'); }
10
+ static function billingPostalCode() { return new Braintree_TextNode('billing_postal_code'); }
11
+ static function billingRegion() { return new Braintree_TextNode('billing_region'); }
12
+ static function billingStreetAddress() { return new Braintree_TextNode('billing_street_address'); }
13
+ static function creditCardCardholderName() { return new Braintree_TextNode('credit_card_cardholderName'); }
14
+ static function customerCompany() { return new Braintree_TextNode('customer_company'); }
15
+ static function customerEmail() { return new Braintree_TextNode('customer_email'); }
16
+ static function customerFax() { return new Braintree_TextNode('customer_fax'); }
17
+ static function customerFirstName() { return new Braintree_TextNode('customer_first_name'); }
18
+ static function customerId() { return new Braintree_TextNode('customer_id'); }
19
+ static function customerLastName() { return new Braintree_TextNode('customer_last_name'); }
20
+ static function customerPhone() { return new Braintree_TextNode('customer_phone'); }
21
+ static function customerWebsite() { return new Braintree_TextNode('customer_website'); }
22
+ static function id() { return new Braintree_TextNode('id'); }
23
+ static function ids() { return new Braintree_MultipleValueNode('ids'); }
24
+ static function orderId() { return new Braintree_TextNode('order_id'); }
25
+ static function paymentMethodToken() { return new Braintree_TextNode('payment_method_token'); }
26
+ static function processorAuthorizationCode() { return new Braintree_TextNode('processor_authorization_code'); }
27
+ static function settlementBatchId() { return new Braintree_TextNode('settlement_batch_id'); }
28
+ static function shippingCompany() { return new Braintree_TextNode('shipping_company'); }
29
+ static function shippingCountryName() { return new Braintree_TextNode('shipping_country_name'); }
30
+ static function shippingExtendedAddress() { return new Braintree_TextNode('shipping_extended_address'); }
31
+ static function shippingFirstName() { return new Braintree_TextNode('shipping_first_name'); }
32
+ static function shippingLastName() { return new Braintree_TextNode('shipping_last_name'); }
33
+ static function shippingLocality() { return new Braintree_TextNode('shipping_locality'); }
34
+ static function shippingPostalCode() { return new Braintree_TextNode('shipping_postal_code'); }
35
+ static function shippingRegion() { return new Braintree_TextNode('shipping_region'); }
36
+ static function shippingStreetAddress() { return new Braintree_TextNode('shipping_street_address'); }
37
+
38
+ static function creditCardExpirationDate() { return new Braintree_EqualityNode('credit_card_expiration_date'); }
39
+
40
+ static function creditCardNumber() { return new Braintree_PartialMatchNode('credit_card_number'); }
41
+
42
+ static function refund() { return new Braintree_KeyValueNode("refund"); }
43
+
44
+ static function amount() { return new Braintree_RangeNode("amount"); }
45
+ static function authorizedAt() { return new Braintree_RangeNode("authorizedAt"); }
46
+ static function authorizationExpiredAt() { return new Braintree_RangeNode("authorizationExpiredAt"); }
47
+ static function createdAt() { return new Braintree_RangeNode("createdAt"); }
48
+ static function failedAt() { return new Braintree_RangeNode("failedAt"); }
49
+ static function gatewayRejectedAt() { return new Braintree_RangeNode("gatewayRejectedAt"); }
50
+ static function processorDeclinedAt() { return new Braintree_RangeNode("processorDeclinedAt"); }
51
+ static function settledAt() { return new Braintree_RangeNode("settledAt"); }
52
+ static function submittedForSettlementAt() { return new Braintree_RangeNode("submittedForSettlementAt"); }
53
+ static function voidedAt() { return new Braintree_RangeNode("voidedAt"); }
54
+
55
+ static function merchantAccountId() { return new Braintree_MultipleValueNode("merchant_account_id"); }
56
+
57
+ static function createdUsing()
58
+ {
59
+ return new Braintree_MultipleValueNode("created_using", array(
60
+ Braintree_Transaction::FULL_INFORMATION,
61
+ Braintree_Transaction::TOKEN
62
+ ));
63
+ }
64
+
65
+ static function creditCardCardType()
66
+ {
67
+ return new Braintree_MultipleValueNode("credit_card_card_type", array(
68
+ Braintree_CreditCard::AMEX,
69
+ Braintree_CreditCard::CARTE_BLANCHE,
70
+ Braintree_CreditCard::CHINA_UNION_PAY,
71
+ Braintree_CreditCard::DINERS_CLUB_INTERNATIONAL,
72
+ Braintree_CreditCard::DISCOVER,
73
+ Braintree_CreditCard::JCB,
74
+ Braintree_CreditCard::LASER,
75
+ Braintree_CreditCard::MAESTRO,
76
+ Braintree_CreditCard::MASTER_CARD,
77
+ Braintree_CreditCard::SOLO,
78
+ Braintree_CreditCard::SWITCH_TYPE,
79
+ Braintree_CreditCard::VISA,
80
+ Braintree_CreditCard::UNKNOWN
81
+ ));
82
+ }
83
+
84
+ static function creditCardCustomerLocation()
85
+ {
86
+ return new Braintree_MultipleValueNode("credit_card_customer_location", array(
87
+ Braintree_CreditCard::INTERNATIONAL,
88
+ Braintree_CreditCard::US
89
+ ));
90
+ }
91
+
92
+ static function source()
93
+ {
94
+ return new Braintree_MultipleValueNode("source", array(
95
+ Braintree_Transaction::API,
96
+ Braintree_Transaction::CONTROL_PANEL,
97
+ Braintree_Transaction::RECURRING,
98
+ ));
99
+ }
100
+
101
+ static function status()
102
+ {
103
+ return new Braintree_MultipleValueNode("status", array(
104
+ Braintree_Transaction::AUTHORIZATION_EXPIRED,
105
+ Braintree_Transaction::AUTHORIZING,
106
+ Braintree_Transaction::AUTHORIZED,
107
+ Braintree_Transaction::GATEWAY_REJECTED,
108
+ Braintree_Transaction::FAILED,
109
+ Braintree_Transaction::PROCESSOR_DECLINED,
110
+ Braintree_Transaction::SETTLED,
111
+ Braintree_Transaction::SETTLING,
112
+ Braintree_Transaction::SUBMITTED_FOR_SETTLEMENT,
113
+ Braintree_Transaction::VOIDED
114
+ ));
115
+ }
116
+
117
+ static function type()
118
+ {
119
+ return new Braintree_MultipleValueNode("type", array(
120
+ Braintree_Transaction::SALE,
121
+ Braintree_Transaction::CREDIT
122
+ ));
123
+ }
124
+ }
includes/lib/Braintree/Braintree/TransparentRedirect.php ADDED
@@ -0,0 +1,327 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ /**
5
+ * Braintree Transparent Redirect module
6
+ *
7
+ * @package Braintree
8
+ * @category Resources
9
+ * @copyright 2010 Braintree Payment Solutions
10
+ */
11
+
12
+ /**
13
+ * Static class providing methods to build Transparent Redirect urls
14
+ *
15
+ * The TransparentRedirect module provides methods to build the tr_data param
16
+ * that must be submitted when using the transparent redirect API.
17
+ * For more information
18
+ * about transparent redirect, see (TODO).
19
+ *
20
+ * You must provide a redirectUrl to which the gateway will redirect the
21
+ * user the action is complete.
22
+ *
23
+ * <code>
24
+ * $trData = Braintree_TransparentRedirect::createCustomerData(array(
25
+ * 'redirectUrl => 'http://example.com/redirect_back_to_merchant_site',
26
+ * ));
27
+ * </code>
28
+ *
29
+ * In addition to the redirectUrl, any data that needs to be protected
30
+ * from user tampering should be included in the trData.
31
+ * For example, to prevent the user from tampering with the transaction
32
+ * amount, include the amount in the trData.
33
+ *
34
+ * <code>
35
+ * $trData = Braintree_TransparentRedirect::transactionData(array(
36
+ * 'redirectUrl' => 'http://example.com/complete_transaction',
37
+ * 'transaction' => array('amount' => '100.00'),
38
+ * ));
39
+ *
40
+ * </code>
41
+ *
42
+ * @package Braintree
43
+ * @category Resources
44
+ * @copyright 2010 Braintree Payment Solutions
45
+ */
46
+ class Braintree_TransparentRedirect
47
+ {
48
+ // Request Kinds
49
+ const CREATE_TRANSACTION = 'create_transaction';
50
+ const CREATE_PAYMENT_METHOD = 'create_payment_method';
51
+ const UPDATE_PAYMENT_METHOD = 'update_payment_method';
52
+ const CREATE_CUSTOMER = 'create_customer';
53
+ const UPDATE_CUSTOMER = 'update_customer';
54
+
55
+ /**
56
+ *
57
+ * @ignore
58
+ */
59
+ private static $_transparentRedirectKeys = 'redirectUrl';
60
+ private static $_createCustomerSignature;
61
+ private static $_updateCustomerSignature;
62
+ private static $_transactionSignature;
63
+ private static $_createCreditCardSignature;
64
+ private static $_updateCreditCardSignature;
65
+
66
+
67
+ /**
68
+ * @ignore
69
+ * don't permit an explicit call of the constructor!
70
+ * (like $t = new Braintree_TransparentRedirect())
71
+ */
72
+ protected function __construct()
73
+ {
74
+
75
+ }
76
+
77
+ /**
78
+ * create signatures for different call types
79
+ * @ignore
80
+ */
81
+ public static function init()
82
+ {
83
+
84
+ self::$_createCustomerSignature = array(
85
+ self::$_transparentRedirectKeys,
86
+ array('customer' => Braintree_Customer::createSignature()),
87
+ );
88
+ self::$_updateCustomerSignature = array(
89
+ self::$_transparentRedirectKeys,
90
+ 'customerId',
91
+ array('customer' => Braintree_Customer::updateSignature()),
92
+ );
93
+ self::$_transactionSignature = array(
94
+ self::$_transparentRedirectKeys,
95
+ array('transaction' => Braintree_Transaction::createSignature()),
96
+ );
97
+ self::$_createCreditCardSignature = array(
98
+ self::$_transparentRedirectKeys,
99
+ array('creditCard' => Braintree_CreditCard::createSignature()),
100
+ );
101
+ self::$_updateCreditCardSignature = array(
102
+ self::$_transparentRedirectKeys,
103
+ 'paymentMethodToken',
104
+ array('creditCard' => Braintree_CreditCard::updateSignature()),
105
+ );
106
+ }
107
+
108
+ public static function confirm($queryString)
109
+ {
110
+ $params = Braintree_TransparentRedirect::parseAndValidateQueryString(
111
+ $queryString
112
+ );
113
+ $confirmationKlasses = array(
114
+ Braintree_TransparentRedirect::CREATE_TRANSACTION => 'Braintree_Transaction',
115
+ Braintree_TransparentRedirect::CREATE_CUSTOMER => 'Braintree_Customer',
116
+ Braintree_TransparentRedirect::UPDATE_CUSTOMER => 'Braintree_Customer',
117
+ Braintree_TransparentRedirect::CREATE_PAYMENT_METHOD => 'Braintree_CreditCard',
118
+ Braintree_TransparentRedirect::UPDATE_PAYMENT_METHOD => 'Braintree_CreditCard'
119
+ );
120
+ return call_user_func(array($confirmationKlasses[$params["kind"]], '_doCreate'),
121
+ '/transparent_redirect_requests/' . $params['id'] . '/confirm',
122
+ array()
123
+ );
124
+ }
125
+
126
+ /**
127
+ * returns the trData string for creating a credit card,
128
+ * @param array $params
129
+ * @return string
130
+ */
131
+ public static function createCreditCardData($params)
132
+ {
133
+ Braintree_Util::verifyKeys(
134
+ self::$_createCreditCardSignature,
135
+ $params
136
+ );
137
+ $params["kind"] = Braintree_TransparentRedirect::CREATE_PAYMENT_METHOD;
138
+ return self::_data($params);
139
+ }
140
+
141
+ /**
142
+ * returns the trData string for creating a customer.
143
+ * @param array $params
144
+ * @return string
145
+ */
146
+ public static function createCustomerData($params)
147
+ {
148
+ Braintree_Util::verifyKeys(
149
+ self::$_createCustomerSignature,
150
+ $params
151
+ );
152
+ $params["kind"] = Braintree_TransparentRedirect::CREATE_CUSTOMER;
153
+ return self::_data($params);
154
+
155
+ }
156
+
157
+ public static function url()
158
+ {
159
+ return Braintree_Configuration::merchantUrl() . "/transparent_redirect_requests";
160
+ }
161
+
162
+ /**
163
+ * returns the trData string for creating a transaction
164
+ * @param array $params
165
+ * @return string
166
+ */
167
+ public static function transactionData($params)
168
+ {
169
+ Braintree_Util::verifyKeys(
170
+ self::$_transactionSignature,
171
+ $params
172
+ );
173
+ $params["kind"] = Braintree_TransparentRedirect::CREATE_TRANSACTION;
174
+ $transactionType = isset($params['transaction']['type']) ?
175
+ $params['transaction']['type'] :
176
+ null;
177
+ if ($transactionType != Braintree_Transaction::SALE && $transactionType != Braintree_Transaction::CREDIT) {
178
+ throw new InvalidArgumentException(
179
+ 'expected transaction[type] of sale or credit, was: ' .
180
+ $transactionType
181
+ );
182
+ }
183
+
184
+ return self::_data($params);
185
+ }
186
+
187
+ /**
188
+ * Returns the trData string for updating a credit card.
189
+ *
190
+ * The paymentMethodToken of the credit card to update is required.
191
+ *
192
+ * <code>
193
+ * $trData = Braintree_TransparentRedirect::updateCreditCardData(array(
194
+ * 'redirectUrl' => 'http://example.com/redirect_here',
195
+ * 'paymentMethodToken' => 'token123',
196
+ * ));
197
+ * </code>
198
+ *
199
+ * @param array $params
200
+ * @return string
201
+ */
202
+ public static function updateCreditCardData($params)
203
+ {
204
+ Braintree_Util::verifyKeys(
205
+ self::$_updateCreditCardSignature,
206
+ $params
207
+ );
208
+ if (!isset($params['paymentMethodToken'])) {
209
+ throw new InvalidArgumentException(
210
+ 'expected params to contain paymentMethodToken.'
211
+ );
212
+ }
213
+ $params["kind"] = Braintree_TransparentRedirect::UPDATE_PAYMENT_METHOD;
214
+ return self::_data($params);
215
+ }
216
+
217
+ /**
218
+ * Returns the trData string for updating a customer.
219
+ *
220
+ * The customerId of the customer to update is required.
221
+ *
222
+ * <code>
223
+ * $trData = Braintree_TransparentRedirect::updateCustomerData(array(
224
+ * 'redirectUrl' => 'http://example.com/redirect_here',
225
+ * 'customerId' => 'customer123',
226
+ * ));
227
+ * </code>
228
+ *
229
+ * @param array $params
230
+ * @return string
231
+ */
232
+ public static function updateCustomerData($params)
233
+ {
234
+ Braintree_Util::verifyKeys(
235
+ self::$_updateCustomerSignature,
236
+ $params
237
+ );
238
+ if (!isset($params['customerId'])) {
239
+ throw new InvalidArgumentException(
240
+ 'expected params to contain customerId of customer to update'
241
+ );
242
+ }
243
+ $params["kind"] = Braintree_TransparentRedirect::UPDATE_CUSTOMER;
244
+ return self::_data($params);
245
+ }
246
+
247
+ public static function parseAndValidateQueryString($queryString)
248
+ {
249
+ // parse the params into an array
250
+ parse_str($queryString, $params);
251
+ // remove the hash
252
+ $queryStringWithoutHash = null;
253
+ if(preg_match('/^(.*)&hash=[a-f0-9]+$/', $queryString, $match)) {
254
+ $queryStringWithoutHash = $match[1];
255
+ }
256
+
257
+ if($params['http_status'] != '200') {
258
+ $message = null;
259
+ if(array_key_exists('bt_message', $params)) {
260
+ $message = $params['bt_message'];
261
+ }
262
+ Braintree_Util::throwStatusCodeException($params['http_status'], $message);
263
+ }
264
+
265
+ // recreate the hash and compare it
266
+ if(self::_hash($queryStringWithoutHash) == $params['hash']) {
267
+ return $params;
268
+ } else {
269
+ throw new Braintree_Exception_ForgedQueryString();
270
+ }
271
+ }
272
+
273
+
274
+ /**
275
+ *
276
+ * @ignore
277
+ */
278
+ private static function _data($params)
279
+ {
280
+ if (!isset($params['redirectUrl'])) {
281
+ throw new InvalidArgumentException(
282
+ 'expected params to contain redirectUrl'
283
+ );
284
+ }
285
+ $params = self::_underscoreKeys($params);
286
+ $now = new DateTime('now', new DateTimeZone('UTC'));
287
+ $trDataParams = array_merge($params,
288
+ array(
289
+ 'api_version' => Braintree_Configuration::API_VERSION,
290
+ 'public_key' => Braintree_Configuration::publicKey(),
291
+ 'time' => $now->format('YmdHis'),
292
+ )
293
+ );
294
+ ksort($trDataParams);
295
+ $trDataSegment = http_build_query($trDataParams, null, '&');
296
+ $trDataHash = self::_hash($trDataSegment);
297
+ return "$trDataHash|$trDataSegment";
298
+ }
299
+
300
+ private static function _underscoreKeys($array)
301
+ {
302
+ foreach($array as $key=>$value)
303
+ {
304
+ $newKey = Braintree_Util::camelCaseToDelimiter($key, '_');
305
+ unset($array[$key]);
306
+ if (is_array($value))
307
+ {
308
+ $array[$newKey] = self::_underscoreKeys($value);
309
+ }
310
+ else
311
+ {
312
+ $array[$newKey] = $value;
313
+ }
314
+ }
315
+ return $array;
316
+ }
317
+
318
+ /**
319
+ * @ignore
320
+ */
321
+ private static function _hash($string)
322
+ {
323
+ return Braintree_Digest::hexDigest($string);
324
+ }
325
+
326
+ }
327
+ Braintree_TransparentRedirect::init();
includes/lib/Braintree/Braintree/Util.php ADDED
@@ -0,0 +1,290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Utility methods
4
+ * PHP version 5
5
+ *
6
+ * @copyright 2010 Braintree Payment Solutions
7
+ */
8
+
9
+ /**
10
+ * Braintree Utility methods
11
+ *
12
+ *
13
+ * @copyright 2010 Braintree Payment Solutions
14
+ */
15
+ class Braintree_Util
16
+ {
17
+ /**
18
+ * extracts an attribute and returns an array of objects
19
+ *
20
+ * extracts the requested element from an array, and converts the contents
21
+ * of its child arrays to objects of type Braintree_$attributeName, or returns
22
+ * an array with a single element containing the value of that array element
23
+ *
24
+ * @param array $attribArray attributes from a search response
25
+ * @param string $attributeName indicates which element of the passed array to extract
26
+ *
27
+ * @return array array of Braintree_$attributeName objects, or a single element array
28
+ */
29
+ public static function extractAttributeAsArray(& $attribArray, $attributeName)
30
+ {
31
+ if(!isset($attribArray[$attributeName])):
32
+ return array();
33
+ endif;
34
+
35
+ // get what should be an array from the passed array
36
+ $data = $attribArray[$attributeName];
37
+ // set up the class that will be used to convert each array element
38
+ $classFactory = self::buildClassName($attributeName) . '::factory';
39
+ if(is_array($data)):
40
+ // create an object from the data in each element
41
+ $objectArray = array_map($classFactory, $data);
42
+ else:
43
+ return array($data);
44
+ endif;
45
+
46
+ unset($attribArray[$attributeName]);
47
+ return $objectArray;
48
+ }
49
+ /**
50
+ * throws an exception based on the type of error
51
+ * @param string $statusCode HTTP status code to throw exception from
52
+ * @throws Braintree_Exception multiple types depending on the error
53
+ *
54
+ */
55
+ public static function throwStatusCodeException($statusCode, $message=null)
56
+ {
57
+ switch($statusCode) {
58
+ case 401:
59
+ throw new Braintree_Exception_Authentication();
60
+ break;
61
+ case 403:
62
+ throw new Braintree_Exception_Authorization($message);
63
+ break;
64
+ case 404:
65
+ throw new Braintree_Exception_NotFound();
66
+ break;
67
+ case 426:
68
+ throw new Braintree_Exception_UpgradeRequired();
69
+ break;
70
+ case 500:
71
+ throw new Braintree_Exception_ServerError();
72
+ break;
73
+ case 503:
74
+ throw new Braintree_Exception_DownForMaintenance();
75
+ break;
76
+ default:
77
+ throw new Braintree_Exception_Unexpected('Unexpected HTTP_RESPONSE #'.$statusCode);
78
+ break;
79
+ }
80
+ }
81
+
82
+ /**
83
+ * removes the Braintree_ header from a classname
84
+ *
85
+ * @param string $name Braintree_ClassName
86
+ * @return camelCased classname minus Braintree_ header
87
+ */
88
+ public static function cleanClassName($name)
89
+ {
90
+ $classNamesToResponseKeys = array(
91
+ 'CreditCard' => 'creditCard',
92
+ 'Customer' => 'customer',
93
+ 'Subscription' => 'subscription',
94
+ 'Transaction' => 'transaction',
95
+ 'CreditCardVerification' => 'verification',
96
+ 'AddOn' => 'addOn',
97
+ 'Discount' => 'discount',
98
+ 'Plan' => 'plan',
99
+ 'Address' => 'address',
100
+ 'SettlementBatchSummary' => 'settlementBatchSummary'
101
+ );
102
+
103
+ $name = str_replace('Braintree_', '', $name);
104
+ return $classNamesToResponseKeys[$name];
105
+ }
106
+
107
+ /**
108
+ *
109
+ * @param string $name className
110
+ * @return string Braintree_ClassName
111
+ */
112
+ public static function buildClassName($name)
113
+ {
114
+ $responseKeysToClassNames = array(
115
+ 'creditCard' => 'CreditCard',
116
+ 'customer' => 'Customer',
117
+ 'subscription' => 'Subscription',
118
+ 'transaction' => 'Transaction',
119
+ 'verification' => 'CreditCardVerification',
120
+ 'addOn' => 'AddOn',
121
+ 'discount' => 'Discount',
122
+ 'plan' => 'Plan',
123
+ 'address' => 'Address',
124
+ 'settlementBatchSummary' => 'SettlementBatchSummary'
125
+ );
126
+
127
+ return 'Braintree_' . $responseKeysToClassNames[$name];
128
+ }
129
+
130
+ /**
131
+ * convert alpha-beta-gamma to alphaBetaGamma
132
+ *
133
+ * @access public
134
+ * @param string $string
135
+ * @return string modified string
136
+ */
137
+ public static function delimiterToCamelCase($string, $delimiter = '[\-\_]')
138
+ {
139
+ return preg_replace('/' . $delimiter . '(\w)/e', 'strtoupper("$1")',$string);
140
+ }
141
+
142
+ /**
143
+ * convert alpha-beta-gamma to alpha_beta_gamma
144
+ *
145
+ * @access public
146
+ * @param string $string
147
+ * @return string modified string
148
+ */
149
+ public static function delimiterToUnderscore($string)
150
+ {
151
+ return preg_replace('/-/', '_', $string);
152
+ }
153
+
154
+
155
+ /**
156
+ * find capitals and convert to delimiter + lowercase
157
+ *
158
+ * @access public
159
+ * @param var $string
160
+ * @return var modified string
161
+ */
162
+ public static function camelCaseToDelimiter($string, $delimiter = '-')
163
+ {
164
+ return preg_replace('/([A-Z])/e', '"' . $delimiter . '" . strtolower("$1")', $string);
165
+ }
166
+
167
+ /**
168
+ *
169
+ * @param array $array associative array to implode
170
+ * @param string $separator (optional, defaults to =)
171
+ * @param string $glue (optional, defaults to ', ')
172
+ */
173
+ public static function implodeAssociativeArray($array, $separator = '=', $glue = ', ')
174
+ {
175
+ // build a new array with joined keys and values
176
+ $tmpArray = null;
177
+ foreach ($array AS $key => $value) {
178
+ $tmpArray[] = $key . $separator . $value;
179
+
180
+ }
181
+ // implode and return the new array
182
+ return (is_array($tmpArray)) ? implode($glue, $tmpArray) : false;
183
+ }
184
+
185
+ public static function attributesToString($attributes) {
186
+ $printableAttribs = array();
187
+ foreach ($attributes AS $key => $value) {
188
+ if (is_array($value)) {
189
+ $pAttrib = Braintree_Util::attributesToString($value);
190
+ } else if ($value instanceof DateTime) {
191
+ $pAttrib = $value->format(DateTime::RFC850);
192
+ } else {
193
+ $pAttrib = $value;
194
+ }
195
+ $printableAttribs[$key] = sprintf('%s', $pAttrib);
196
+ }
197
+ return Braintree_Util::implodeAssociativeArray($printableAttribs);
198
+ }
199
+
200
+ /**
201
+ * verify user request structure
202
+ *
203
+ * compares the expected signature of a gateway request
204
+ * against the actual structure sent by the user
205
+ *
206
+ * @param array $signature
207
+ * @param array $attributes
208
+ */
209
+ public static function verifyKeys($signature, $attributes)
210
+ {
211
+ $validKeys = self::_flattenArray($signature);
212
+ $userKeys = self::_flattenUserKeys($attributes);
213
+ $invalidKeys = array_diff($userKeys, $validKeys);
214
+ $invalidKeys = self::_removeWildcardKeys($validKeys, $invalidKeys);
215
+
216
+ if(!empty($invalidKeys)) {
217
+ asort($invalidKeys);
218
+ $sortedList = join(', ', $invalidKeys);
219
+ throw new InvalidArgumentException('invalid keys: '. $sortedList);
220
+ }
221
+ }
222
+ /**
223
+ * flattens a numerically indexed nested array to a single level
224
+ * @param array $keys
225
+ * @param string $namespace
226
+ * @return array
227
+ */
228
+ private static function _flattenArray($keys, $namespace = null)
229
+ {
230
+ $flattenedArray = array();
231
+ foreach($keys AS $key) {
232
+ if(is_array($key)) {
233
+ $theKeys = array_keys($key);
234
+ $theValues = array_values($key);
235
+ $scope = $theKeys[0];
236
+ $fullKey = empty($namespace) ? $scope : $namespace . '[' . $scope . ']';
237
+ $flattenedArray = array_merge($flattenedArray, self::_flattenArray($theValues[0], $fullKey));
238
+ } else {
239
+ $fullKey = empty($namespace) ? $key : $namespace . '[' . $key . ']';
240
+ $flattenedArray[] = $fullKey;
241
+ }
242
+ }
243
+ sort($flattenedArray);
244
+ return $flattenedArray;
245
+ }
246
+
247
+ private static function _flattenUserKeys($keys, $namespace = null)
248
+ {
249
+ $flattenedArray = array();
250
+
251
+ foreach($keys AS $key => $value) {
252
+ $fullKey = empty($namespace) ? $key : $namespace;
253
+ if (!is_numeric($key) && $namespace != null) {
254
+ $fullKey .= '[' . $key . ']';
255
+ }
256
+ if (is_numeric($key) && is_string($value)) {
257
+ $fullKey .= '[' . $value . ']';
258
+ }
259
+ if(is_array($value)) {
260
+ $more = self::_flattenUserKeys($value, $fullKey);
261
+ $flattenedArray = array_merge($flattenedArray, $more);
262
+ } else {
263
+ $flattenedArray[] = $fullKey;
264
+ }
265
+ }
266
+ sort($flattenedArray);
267
+ return $flattenedArray;
268
+ }
269
+
270
+ /**
271
+ * removes wildcard entries from the invalid keys array
272
+ * @param array $validKeys
273
+ * @param <array $invalidKeys
274
+ * @return array
275
+ */
276
+ private static function _removeWildcardKeys($validKeys, $invalidKeys)
277
+ {
278
+ foreach($validKeys AS $key) {
279
+ if (stristr($key, '[_anyKey_]')) {
280
+ $wildcardKey = str_replace('[_anyKey_]', '', $key);
281
+ foreach ($invalidKeys AS $index => $invalidKey) {
282
+ if (stristr($invalidKey, $wildcardKey)) {
283
+ unset($invalidKeys[$index]);
284
+ }
285
+ }
286
+ }
287
+ }
288
+ return $invalidKeys;
289
+ }
290
+ }
includes/lib/Braintree/Braintree/Version.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Library Version
4
+ *
5
+ * @copyright 2010 Braintree Payment Solutions
6
+ */
7
+
8
+ /**
9
+ * stores version information about the Braintree library
10
+ *
11
+ *
12
+ * @copyright 2010 Braintree Payment Solutions
13
+ */
14
+ final class Braintree_Version
15
+ {
16
+ /**
17
+ * class constants
18
+ */
19
+ const MAJOR = 2;
20
+ const MINOR = 19;
21
+ const TINY = 0;
22
+
23
+ /**
24
+ * @ignore
25
+ * @access protected
26
+ */
27
+ protected function __construct()
28
+ {
29
+ }
30
+
31
+ /**
32
+ *
33
+ * @return string the current library version
34
+ */
35
+ public static function get()
36
+ {
37
+ return self::MAJOR.'.'.self::MINOR.'.'.self::TINY;
38
+ }
39
+ }
includes/lib/Braintree/Braintree/WebhookNotification.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_WebhookNotification extends Braintree
3
+ {
4
+ const SUBSCRIPTION_CANCELED = 'subscription_canceled';
5
+ const SUBSCRIPTION_CHARGED_SUCCESSFULLY = 'subscription_charged_successfully';
6
+ const SUBSCRIPTION_CHARGED_UNSUCCESSFULLY = 'subscription_charged_unsuccessfully';
7
+ const SUBSCRIPTION_EXPIRED = 'subscription_expired';
8
+ const SUBSCRIPTION_TRIAL_ENDED = 'subscription_trial_ended';
9
+ const SUBSCRIPTION_WENT_ACTIVE = 'subscription_went_active';
10
+ const SUBSCRIPTION_WENT_PAST_DUE = 'subscription_went_past_due';
11
+
12
+ public static function parse($signature, $payload)
13
+ {
14
+ self::_validateSignature($signature, $payload);
15
+
16
+ $xml = base64_decode($payload);
17
+ $attributes = Braintree_Xml::buildArrayFromXml($xml);
18
+ return self::factory($attributes['notification']);
19
+ }
20
+
21
+ public static function verify($challenge)
22
+ {
23
+ $publicKey = Braintree_Configuration::publicKey();
24
+ $digest = Braintree_Digest::hexDigest($challenge);
25
+ return "{$publicKey}|{$digest}";
26
+ }
27
+
28
+ public static function factory($attributes)
29
+ {
30
+ $instance = new self();
31
+ $instance->_initialize($attributes);
32
+ return $instance;
33
+ }
34
+
35
+ private static function _matchingSignature($signaturePairs)
36
+ {
37
+ foreach ($signaturePairs as $pair)
38
+ {
39
+ $components = preg_split("/\|/", $pair);
40
+ if ($components[0] == Braintree_Configuration::publicKey()) {
41
+ return $components[1];
42
+ }
43
+ }
44
+
45
+ return null;
46
+ }
47
+
48
+ private static function _validateSignature($signature, $payload)
49
+ {
50
+ $signaturePairs = preg_split("/&/", $signature);
51
+ $matchingSignature = self::_matchingSignature($signaturePairs);
52
+
53
+ $payloadSignature = Braintree_Digest::hexDigest($payload);
54
+ if (!Braintree_Digest::secureCompare($matchingSignature, $payloadSignature)) {
55
+ throw new Braintree_Exception_InvalidSignature("webhook notification signature invalid");
56
+ }
57
+ }
58
+
59
+ protected function _initialize($attributes)
60
+ {
61
+ $this->_attributes = $attributes;
62
+ if (isset($attributes['subject']) && isset($attributes['subject']['subscription'])) {
63
+ $this->_set('subscription', Braintree_Subscription::factory($attributes['subject']['subscription']));
64
+ }
65
+ }
66
+ }
includes/lib/Braintree/Braintree/WebhookTesting.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Braintree_WebhookTesting
3
+ {
4
+ public static function sampleNotification($kind, $id)
5
+ {
6
+ $payload = base64_encode(self::_sampleXml($kind, $id));
7
+ $signature = Braintree_Configuration::publicKey() . "|" . Braintree_Digest::hexDigest($payload);
8
+
9
+ return array(
10
+ 'signature' => $signature,
11
+ 'payload' => $payload
12
+ );
13
+ }
14
+
15
+ private static function _sampleXml($kind, $id)
16
+ {
17
+ $subjectXml = self::_subscriptionSampleXml($id);
18
+ $timestamp = self::_timestamp();
19
+ return "
20
+ <notification>
21
+ <timestamp type=\"datetime\">{$timestamp}</timestamp>
22
+ <kind>{$kind}</kind>
23
+ <subject>{$subjectXml}</subject>
24
+ </notification>
25
+ ";
26
+ }
27
+
28
+ private static function _subscriptionSampleXml($id)
29
+ {
30
+ return "
31
+ <subscription>
32
+ <id>{$id}</id>
33
+ <transactions type=\"array\">
34
+ </transactions>
35
+ <add_ons type=\"array\">
36
+ </add_ons>
37
+ <discounts type=\"array\">
38
+ </discounts>
39
+ </subscription>
40
+ ";
41
+ }
42
+
43
+ private static function _timestamp()
44
+ {
45
+ $originalZone = date_default_timezone_get();
46
+ date_default_timezone_set('UTC');
47
+ $timestamp = strftime('%Y-%m-%dT%TZ');
48
+ date_default_timezone_set($originalZone);
49
+
50
+ return $timestamp;
51
+ }
52
+ }
includes/lib/Braintree/Braintree/Xml.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Braintree Xml parser and generator
4
+ * PHP version 5
5
+ *
6
+ * @copyright 2010 Braintree Payment Solutions
7
+ */
8
+
9
+ /**
10
+ * superclass for Braintree XML parsing and generation
11
+ *
12
+ * @copyright 2010 Braintree Payment Solutions
13
+ */
14
+ final class Braintree_Xml
15
+ {
16
+ /**
17
+ * @ignore
18
+ */
19
+ protected function __construct()
20
+ {
21
+
22
+ }
23
+
24
+ /**
25
+ *
26
+ * @param string $xml
27
+ * @return array
28
+ */
29
+ public static function buildArrayFromXml($xml)
30
+ {
31
+ return Braintree_Xml_Parser::arrayFromXml($xml);
32
+ }
33
+
34
+ /**
35
+ *
36
+ * @param array $array
37
+ * @return string
38
+ */
39
+ public static function buildXmlFromArray($array)
40
+ {
41
+ return Braintree_Xml_Generator::arrayToXml($array);
42
+ }
43
+ }
includes/lib/Braintree/Braintree/Xml/Generator.php ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP version 5
4
+ *
5
+ * @copyright 2010 Braintree Payment Solutions
6
+ */
7
+
8
+ /**
9
+ * Generates XML output from arrays using PHP's
10
+ * built-in XMLWriter
11
+ *
12
+ * @copyright 2010 Braintree Payment Solutions
13
+ */
14
+ class Braintree_Xml_Generator
15
+ {
16
+ /**
17
+ * arrays passed to this method should have a single root element
18
+ * with an array as its value
19
+ * @param array $aData the array of data
20
+ * @return var XML string
21
+ */
22
+ public static function arrayToXml($aData)
23
+ {
24
+ // set up the XMLWriter
25
+ $writer = new XMLWriter();
26
+ $writer->openMemory();
27
+
28
+ $writer->setIndent(true);
29
+ $writer->setIndentString(' ');
30
+ $writer->startDocument('1.0', 'UTF-8');
31
+
32
+ // get the root element name
33
+ $aKeys = array_keys($aData);
34
+ $rootElementName = $aKeys[0];
35
+ // open the root element
36
+ $writer->startElement(Braintree_Util::camelCaseToDelimiter($rootElementName));
37
+ // create the body
38
+ self::_createElementsFromArray($writer, $aData[$rootElementName], $rootElementName);
39
+
40
+ // close the root element and document
41
+ $writer->endElement();
42
+ $writer->endDocument();
43
+
44
+ // send the output as string
45
+ return $writer->outputMemory();
46
+ }
47
+
48
+ /**
49
+ * Construct XML elements with attributes from an associative array.
50
+ *
51
+ * @access protected
52
+ * @static
53
+ * @param object $writer XMLWriter object
54
+ * @param array $aData contains attributes and values
55
+ * @return none
56
+ */
57
+ private static function _createElementsFromArray(&$writer, $aData)
58
+ {
59
+ if (!is_array($aData)) {
60
+ if (is_bool($aData)) {
61
+ $writer->text($aData ? 'true' : 'false');
62
+ } else {
63
+ $writer->text($aData);
64
+ }
65
+ return;
66
+ }
67
+ foreach ($aData AS $index => $element) {
68
+ // convert the style back to gateway format
69
+ $elementName = Braintree_Util::camelCaseToDelimiter($index, '-');
70
+ // handle child elements
71
+ $writer->startElement($elementName);
72
+ if (is_array($element)) {
73
+ if (array_key_exists(0, $element) || empty($element)) {
74
+ $writer->writeAttribute('type', 'array');
75
+ foreach ($element AS $ignored => $itemInArray) {
76
+ $writer->startElement('item');
77
+ self::_createElementsFromArray($writer, $itemInArray);
78
+ $writer->endElement();
79
+ }
80
+ }
81
+ else {
82
+ self::_createElementsFromArray($writer, $element);
83
+ }
84
+ } else {
85
+ // generate attributes as needed
86
+ $attribute = self::_generateXmlAttribute($element);
87
+ if (is_array($attribute)) {
88
+ $writer->writeAttribute($attribute[0], $attribute[1]);
89
+ $element = $attribute[2];
90
+ }
91
+ $writer->text($element);
92
+ }
93
+ $writer->endElement();
94
+ }
95
+ }
96
+
97
+ /**
98
+ * convert passed data into an array of attributeType, attributeName, and value
99
+ * dates sent as DateTime objects will be converted to strings
100
+ * @access protected
101
+ * @param mixed $value
102
+ * @return array attributes and element value
103
+ */
104
+ private static function _generateXmlAttribute($value)
105
+ {
106
+ if ($value instanceof DateTime) {
107
+ return array('type', 'datetime', self::_dateTimeToXmlTimestamp($value));
108
+ }
109
+ if (is_int($value)) {
110
+ return array('type', 'integer', $value);
111
+ }
112
+ if (is_bool($value)) {
113
+ return array('type', 'boolean', ($value ? 'true' : 'false'));
114
+ }
115
+ if ($value === NULL) {
116
+ return array('nil', 'true', $value);
117
+ }
118
+ }
119
+ /**
120
+ * converts datetime back to xml schema format
121
+ * @access protected
122
+ * @param object $dateTime
123
+ * @return var XML schema formatted timestamp
124
+ */
125
+ private static function _dateTimeToXmlTimestamp($dateTime)
126
+ {
127
+ $dateTime->setTimeZone(new DateTimeZone('UTC'));
128
+ return ($dateTime->format('Y-m-d\TH:i:s') . 'Z');
129
+ }
130
+
131
+ private static function _castDateTime($string)
132
+ {
133
+ try {
134
+ if (empty($string)) {
135
+ return false;
136
+ }
137
+ $dateTime = new DateTime($string);
138
+ return self::_dateTimeToXmlTimestamp($dateTime);
139
+ } catch (Exception $e) {
140
+ // not a datetime
141
+ return false;
142
+ }
143
+ }
144
+ }
includes/lib/Braintree/Braintree/Xml/Parser.php ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Braintree XML Parser
5
+ *
6
+ * @copyright 2010 Braintree Payment Solutions
7
+ */
8
+ /**
9
+ * Parses incoming Xml into arrays using PHP's
10
+ * built-in SimpleXML, and its extension via
11
+ * Iterator, SimpleXMLIterator
12
+ *
13
+ * @copyright 2010 Braintree Payment Solutions
14
+ */
15
+ class Braintree_Xml_Parser
16
+ {
17
+
18
+ private static $_xmlRoot;
19
+ private static $_responseType;
20
+
21
+ /**
22
+ * sets up the SimpleXMLIterator and starts the parsing
23
+ * @access public
24
+ * @param string $xml
25
+ * @return array array mapped to the passed xml
26
+ */
27
+ public static function arrayFromXml($xml)
28
+ {
29
+ // SimpleXML provides the root information on construct
30
+ $iterator = new SimpleXMLIterator($xml);
31
+ $xmlRoot = Braintree_Util::delimiterToCamelCase($iterator->getName());
32
+ $type = $iterator->attributes()->type;
33
+
34
+ self::$_xmlRoot = $iterator->getName();
35
+ self::$_responseType = $type;
36
+
37
+ // return the mapped array with the root element as the header
38
+ return array($xmlRoot => self::_iteratorToArray($iterator));
39
+
40
+ }
41
+
42
+ /**
43
+ * processes SimpleXMLIterator objects recursively
44
+ *
45
+ * @access protected
46
+ * @param object $iterator
47
+ * @return array xml converted to array
48
+ */
49
+ private static function _iteratorToArray($iterator)
50
+ {
51
+ $xmlArray = array();
52
+ $value = null;
53
+
54
+ // rewind the iterator and check if the position is valid
55
+ // if not, return the string it contains
56
+ $iterator->rewind();
57
+ if (!$iterator->valid()) {
58
+ return self::_typecastXmlValue($iterator);
59
+ }
60
+ for ($iterator->rewind(); $iterator->valid(); $iterator->next()) {
61
+
62
+ $tmpArray = null;
63
+ $value = null;
64
+
65
+ // get the attribute type string for use in conditions below
66
+ $attributeType = $iterator->attributes()->type;
67
+
68
+ // extract the parent element via xpath query
69
+ $parentElement = $iterator->xpath($iterator->key() . '/..');
70
+ if ($parentElement[0] instanceof SimpleXMLIterator) {
71
+ $parentElement = $parentElement[0];
72
+ $parentKey = Braintree_Util::delimiterToCamelCase($parentElement->getName());
73
+ } else {
74
+ $parentElement = null;
75
+ }
76
+
77
+
78
+ if ($parentKey == "customFields") {
79
+ $key = Braintree_Util::delimiterToUnderscore($iterator->key());
80
+ } else {
81
+ $key = Braintree_Util::delimiterToCamelCase($iterator->key());
82
+ }
83
+
84
+ // process children recursively
85
+ if ($iterator->hasChildren()) {
86
+ // return the child elements
87
+ $value = self::_iteratorToArray($iterator->current());
88
+
89
+ // if the element is an array type,
90
+ // use numeric keys to allow multiple values
91
+ if ($attributeType != 'array') {
92
+ $tmpArray[$key] = $value;
93
+ }
94
+ } else {
95
+ // cast values according to attributes
96
+ $tmpArray[$key] = self::_typecastXmlValue($iterator->current());
97
+ }
98
+
99
+ // set the output string
100
+ $output = isset($value) ? $value : $tmpArray[$key];
101
+
102
+ // determine if there are multiple tags of this name at the same level
103
+ if (isset($parentElement) &&
104
+ ($parentElement->attributes()->type == 'collection') &&
105
+ $iterator->hasChildren()) {
106
+ $xmlArray[$key][] = $output;
107
+ continue;
108
+ }
109
+
110
+ // if the element was an array type, output to a numbered key
111
+ // otherwise, use the element name
112
+ if ($attributeType == 'array') {
113
+ $xmlArray[] = $output;
114
+ } else {
115
+ $xmlArray[$key] = $output;
116
+ }
117
+ }
118
+
119
+ return $xmlArray;
120
+ }
121
+
122
+ /**
123
+ * typecast xml value based on attributes
124
+ * @param object $valueObj SimpleXMLElement
125
+ * @return mixed value for placing into array
126
+ */
127
+ private static function _typecastXmlValue($valueObj)
128
+ {
129
+ // get the element attributes
130
+ $attribs = $valueObj->attributes();
131
+ // the element is null, so jump out here
132
+ if (isset($attribs->nil) && $attribs->nil) {
133
+ return null;
134
+ }
135
+ // switch on the type attribute
136
+ // switch works even if $attribs->type isn't set
137
+ switch ($attribs->type) {
138
+ case 'datetime':
139
+ return self::_timestampToUTC((string) $valueObj);
140
+ break;
141
+ case 'date':
142
+ return new DateTime((string)$valueObj);
143
+ break;
144
+ case 'integer':
145
+ return (int) $valueObj;
146
+ break;
147
+ case 'boolean':
148
+ $value = (string) $valueObj;
149
+ // look for a number inside the string
150
+ if(is_numeric($value)) {
151
+ return (bool) $value;
152
+ } else {
153
+ // look for the string "true", return false in all other cases
154
+ return ($value != "true") ? FALSE : TRUE;
155
+ }
156
+ break;
157
+ case 'array':
158
+ return array();
159
+ default:
160
+ return (string) $valueObj;
161
+ }
162
+
163
+ }
164
+
165
+ /**
166
+ * convert xml timestamps into DateTime
167
+ * @param string $timestamp
168
+ * @return string UTC formatted datetime string
169
+ */
170
+ private static function _timestampToUTC($timestamp)
171
+ {
172
+ $tz = new DateTimeZone('UTC');
173
+ // strangely DateTime requires an explicit set below
174
+ // to show the proper time zone
175
+ $dateTime = new DateTime($timestamp, $tz);
176
+ $dateTime->setTimezone($tz);
177
+ return $dateTime;
178
+ }
179
+ }
includes/lib/Braintree/ssl/sandbox_braintreegateway_com.ca.crt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Subject: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 2 Policy Validation Authority, CN=http://www.valicert.com//emailAddress=info@valicert.com
2
+ -----BEGIN CERTIFICATE-----
3
+ MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
4
+ IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
5
+ BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
6
+ aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
7
+ 9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
8
+ NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
9
+ azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
10
+ YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
11
+ Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
12
+ cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
13
+ dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
14
+ WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
15
+ v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
16
+ UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
17
+ IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
18
+ W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
19
+ -----END CERTIFICATE-----
includes/lib/Braintree/ssl/www_braintreegateway_com.ca.crt ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Subject: O=Entrust.net, OU=www.entrust.net/GCCA_CPS incorp. by ref. (limits liab.), OU=(c) 2000 Entrust.net Limited, CN=Entrust.net Client Certification Authority
2
+ -----BEGIN CERTIFICATE-----
3
+ MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UE
4
+ ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NB
5
+ X0NQUyBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT
6
+ HChjKSAyMDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1
7
+ c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAy
8
+ MDcxNjE2NDBaFw0yMDAyMDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0
9
+ Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29y
10
+ cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg
11
+ RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xp
12
+ ZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
13
+ A4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7NySpj10InJrWPNTTVRaoTU
14
+ rcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0iJBeAZfv6lOm3fzB
15
+ 3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn5JVn1j+SgF7y
16
+ NH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHdBgNVHR8E
17
+ gdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUAw
18
+ PgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy
19
+ ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0
20
+ Lm5ldCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2Vy
21
+ dGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw
22
+ IoAPMjAwMDAyMDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQD
23
+ AgEGMB8GA1UdIwQYMBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQW
24
+ BBSEi3T9xY3A/ydtIDdFfP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2
25
+ fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWA
26
+ O9GK9Q6nIMstZVXQkvTnhLUGJoMShAusO7JE7r3PQNsgDrpuFOow4DtifH+L
27
+ a3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/GpsKkMWr2tGzhtQvJFJcem3G8v7l
28
+ TRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKdzmVml64mXg==
29
+ -----END CERTIFICATE-----
30
+
31
+ Subject: O=Entrust.net, OU=www.entrust.net/SSL_CPS incorp. by ref. (limits liab.), OU=(c) 2000 Entrust.net Limited, CN=Entrust.net Secure Server Certification Authority
32
+ -----BEGIN CERTIFICATE-----
33
+ MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UE
34
+ ChMLRW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xf
35
+ Q1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
36
+ KGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVz
37
+ dC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
38
+ Fw0wMDAyMDQxNzIwMDBaFw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtF
39
+ bnRydXN0Lm5ldDE/MD0GA1UECxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMg
40
+ aW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykg
41
+ MjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5l
42
+ dCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0G
43
+ CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO8GCGD9JYf9Mzly0XonUw
44
+ tZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaBbL3+qPZ1V1eMkGxK
45
+ wz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2dWcTC5/oVzbI
46
+ XQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4QgEBBAQD
47
+ AgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoTC0Vu
48
+ dHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp
49
+ bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAy
50
+ MDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0
51
+ IFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNV
52
+ BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIw
53
+ NDE3NTAwMFowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc
54
+ /vuLkpyw8m4iMB0GA1UdDgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNV
55
+ HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkq
56
+ hkiG9w0BAQQFAAOBgQBi24GRzsiad0Iv7L0no1MPUBvqTpLwqa+poLpIYcvv
57
+ yQbvH9X07t9WLebKahlzqlO+krNQAraFJnJj2HVQYnUUt7NQGj/KEQALhUVp
58
+ bbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1UyrrJzOCE98g+EZfTYAkYvAX/
59
+ bIkz8OwVDw==
60
+ -----END CERTIFICATE-----
61
+
62
+ Subject: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048)
63
+ -----BEGIN CERTIFICATE-----
64
+ MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UE
65
+ ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNf
66
+ MjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT
67
+ HChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1
68
+ c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEy
69
+ MjQxNzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0
70
+ Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29y
71
+ cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkg
72
+ RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2Vy
73
+ dGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEF
74
+ AAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4
75
+ QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/EC
76
+ DNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj
77
+ /L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLP
78
+ KQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZd
79
+ enoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
80
+ 4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB
81
+ 0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJ
82
+ FrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B
83
+ AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFh
84
+ fGPjK50xA3B20qMooPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVU
85
+ KcgF7bISKo30Axv/55IQh7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaoho
86
+ wXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2
87
+ +z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof888
88
+ 6ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ==
89
+ -----END CERTIFICATE-----
90
+
91
+ Subject: C=US, O=Entrust.net, OU=www.entrust.net/Client_CA_Info/CPS incorp. by ref. limits liab., OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Client Certification Authority
92
+ -----BEGIN CERTIFICATE-----
93
+ MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE
94
+ BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50
95
+ cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs
96
+ aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp
97
+ bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0
98
+ aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa
99
+ MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV
100
+ BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw
101
+ LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50
102
+ cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50
103
+ IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL
104
+ ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv
105
+ x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV
106
+ iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173
107
+ iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw
108
+ ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50
109
+ cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff
110
+ SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE
111
+ CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50
112
+ cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD
113
+ VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D
114
+ bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx
115
+ MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW
116
+ /O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG
117
+ A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
118
+ hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ
119
+ OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU
120
+ ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE
121
+ PHayXOw=
122
+ -----END CERTIFICATE-----
123
+
124
+ Subject: C=US, O=Entrust.net, OU=www.entrust.net/CPS incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Secure Server Certification Authority
125
+ -----BEGIN CERTIFICATE-----
126
+ MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UE
127
+ BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50
128
+ cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
129
+ MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UE
130
+ AxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1
131
+ dGhvcml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQsw
132
+ CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3
133
+ dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlh
134
+ Yi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTow
135
+ OAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
136
+ b24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0
137
+ VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55