s2Member Framework (Member Roles, Capabilities, Membership, PayPal Members) - Version 3.0

Version Description

Upgrade highly recommended. After upgrading, go to: s2Member -> PayPal Options -> EOT Behavior to enable the Auto-EOT System ( new ). For full details, please read the Changelog.

=

Download this release

Release Info

Developer PriMoThemes
Plugin Icon 128x128 s2Member Framework (Member Roles, Capabilities, Membership, PayPal Members)
Version 3.0
Comparing to
See all releases

Code changes from version 2.9.4 to 3.0

Files changed (53) hide show
  1. includes/functions/auto-eots.inc.php +137 -0
  2. includes/functions/catg-level-access.inc.php +32 -28
  3. includes/functions/constants.inc.php +4 -2
  4. includes/functions/file-download-access.inc.php +3 -3
  5. includes/functions/ip-restrictions.inc.php +61 -0
  6. includes/functions/js-globals.inc.php +3 -1
  7. includes/functions/list-servers.inc.php +2 -2
  8. includes/functions/login-redirection.inc.php +9 -6
  9. includes/functions/menu-pages.inc.php +9 -5
  10. includes/functions/nocache.inc.php +1 -0
  11. includes/functions/page-level-access.inc.php +12 -12
  12. includes/functions/paypal-notify.inc.php +317 -151
  13. includes/functions/paypal-postvars.inc.php +0 -73
  14. includes/functions/paypal-return.inc.php +112 -158
  15. includes/functions/paypal-utilities.inc.php +203 -0
  16. includes/functions/post-level-access.inc.php +11 -8
  17. includes/functions/ptag-level-access.inc.php +16 -16
  18. includes/functions/register-access.inc.php +28 -14
  19. includes/functions/ruri-level-access.inc.php +16 -12
  20. includes/functions/shortcodes.inc.php +35 -16
  21. includes/functions/sp-access.inc.php +56 -19
  22. includes/functions/tracking-codes.inc.php +132 -0
  23. includes/functions/user-deletions.inc.php +8 -5
  24. includes/functions/user-has-wp-role.inc.php +39 -0
  25. includes/functions/user-notes.inc.php +53 -0
  26. includes/functions/users-list.inc.php +53 -14
  27. includes/functions/utilities.inc.php +61 -10
  28. includes/hooks.inc.php +9 -0
  29. includes/menu-pages/api-ops.inc.php +60 -60
  30. includes/menu-pages/buttons.inc.php +75 -42
  31. includes/menu-pages/code-samples/idev-sp-tracking-code.php +6 -0
  32. includes/menu-pages/code-samples/sas-sp-tracking-code.php +6 -0
  33. includes/menu-pages/code-samples/version.php +4 -0
  34. includes/menu-pages/els-ops.inc.php +1 -1
  35. includes/menu-pages/menu-pages.js +35 -23
  36. includes/menu-pages/options.inc.php +164 -91
  37. includes/menu-pages/paypal-ops.inc.php +58 -36
  38. includes/menu-pages/scripting.inc.php +7 -2
  39. includes/menu-pages/start.inc.php +6 -12
  40. includes/menu-pages/trk-ops.inc.php +81 -30
  41. includes/syscon.inc.php +94 -59
  42. includes/templates/buttons/sp-button.html +1 -1
  43. includes/templates/options/currencies.html +26 -0
  44. includes/templates/options/index.php +0 -0
  45. includes/templates/options/membership-modification-levels.html +18 -0
  46. includes/templates/options/membership-regular-terms.html +64 -0
  47. includes/templates/options/membership-trial-terms.html +4 -0
  48. includes/templates/options/sp-hours.html +38 -0
  49. includes/templates/shortcodes/c-shortcode.html +1 -1
  50. includes/templates/shortcodes/shortcode.html +1 -1
  51. includes/templates/shortcodes/sp-shortcode.html +1 -1
  52. readme.txt +47 -15
  53. s2member.php +4 -5
includes/functions/auto-eots.inc.php ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright: © 2009 WebSharks, Inc. ( coded in the USA )
4
+ <mailto:support@websharks-inc.com> <http://www.websharks-inc.com/>
5
+
6
+ Released under the terms of the GNU General Public License.
7
+ You should have received a copy of the GNU General Public License,
8
+ along with this software. In the main directory, see: /licensing/
9
+ If not, see: <http://www.gnu.org/licenses/>.
10
+ */
11
+ /*
12
+ Direct access denial.
13
+ */
14
+ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
+ exit;
16
+ /*
17
+ Function processed by WP_Cron. This handles Auto-EOTs.
18
+ If you have a HUGE user-base, increase the max eots per process.
19
+ To increase, use: add_filter("s2member_auto_eots_per_process");
20
+ */
21
+ function ws_plugin__s2member_auto_eot_system ($per_process = 10)
22
+ {
23
+ global $wpdb; /* Need global DB obj. */
24
+ /**/
25
+ do_action ("s2member_before_auto_eot_system");
26
+ /**/
27
+ include_once ABSPATH . "wp-admin/includes/admin.php"; /* Get Admin APIs. */
28
+ /**/
29
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["auto_eot_system_enabled"]) /* Enabled? */
30
+ {
31
+ $per_process = apply_filters ("s2member_auto_eot_system_per_process", $per_process);
32
+ /**/
33
+ if ($eots = $wpdb->get_results ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = 's2member_auto_eot_time' AND `meta_value` <= '" . $wpdb->escape (strtotime ("now")) . "' LIMIT " . $per_process))
34
+ {
35
+ foreach ($eots as $eot) /* Go through the array of eots. We need to (demote|delete) each of them. */
36
+ {
37
+ $user_id = $eot->user_id; /* Grab the user ID value from the query. */
38
+ /**/
39
+ $user = new WP_User ($user_id); /* Acquire user object. */
40
+ /**/
41
+ delete_usermeta ($user_id, "s2member_auto_eot_time"); /* Always remove this. */
42
+ /* Removing this prevents re-runs on non WP Roles. Which are scanned for next. */
43
+ /**/
44
+ if (!ws_plugin__s2member_user_has_wp_role ($user)) /* Non WP Roles. */
45
+ {
46
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_eot_behavior"] === "demote")
47
+ {
48
+ $user->set_role ("subscriber");
49
+ /**/
50
+ $subscr_id = get_usermeta ($user_id, "s2member_subscr_id");
51
+ $custom = get_usermeta ($user_id, "s2member_custom");
52
+ /**/
53
+ delete_usermeta ($user_id, "s2member_custom");
54
+ delete_usermeta ($user_id, "s2member_subscr_id");
55
+ delete_usermeta ($user_id, "s2member_last_payment_time");
56
+ delete_usermeta ($user_id, "s2member_auto_eot_time");
57
+ /**/
58
+ foreach ($user->allcaps as $cap => $cap_enabled)
59
+ if (preg_match ("/^access_s2member_ccap_/", $cap))
60
+ $user->remove_cap ($ccap = $cap);
61
+ /**/
62
+ delete_usermeta ($user_id, "s2member_file_download_access_arc");
63
+ delete_usermeta ($user_id, "s2member_file_download_access_log");
64
+ /**/
65
+ ws_plugin__s2member_append_user_notes ($user_id, "Demoted by s2Member: " . date ("D M j, Y g:i a T"));
66
+ /**/
67
+ if ($subscr_id && $custom && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_del_notification_urls"] && is_array ($cv = preg_split ("/\|/", $custom)))
68
+ {
69
+ foreach (preg_split ("/[\r\n\t]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_del_notification_urls"]) as $url) /* Handle EOT Notifications. */
70
+ /**/
71
+ if (($url = preg_replace ("/%%cv([0-9]+)%%/ei", 'urlencode(trim($cv[$1]))', $url)) && ($url = preg_replace ("/%%subscr_id%%/i", urlencode ($subscr_id), $url)))
72
+ if (($url = preg_replace ("/%%user_first_name%%/i", urlencode ($user->first_name), $url)) && ($url = preg_replace ("/%%user_last_name%%/i", urlencode ($user->last_name), $url)))
73
+ if (($url = preg_replace ("/%%user_full_name%%/i", urlencode (trim ($user->first_name . " " . $user->last_name)), $url)))
74
+ if (($url = preg_replace ("/%%user_email%%/i", urlencode ($user->user_email), $url)))
75
+ /**/
76
+ if (($url = trim ($url))) /* Make sure it is not empty. */
77
+ ws_plugin__s2member_curlpsr ($url, "s2member=1");
78
+ }
79
+ /**/
80
+ do_action ("s2member_during_auto_eot_system_during_demote");
81
+ }
82
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_eot_behavior"] === "delete")
83
+ {
84
+ wp_delete_user ($user_id); /* Triggers: `ws_plugin__s2member_handle_user_deletions()` */
85
+ /* `ws_plugin__s2member_handle_user_deletions()` triggers `eot_del_notification_urls` */
86
+ /**/
87
+ do_action ("s2member_during_auto_eot_system_during_delete");
88
+ }
89
+ /**/
90
+ do_action ("s2member_during_auto_eot_system");
91
+ }
92
+ }
93
+ }
94
+ }
95
+ /**/
96
+ do_action ("s2member_after_auto_eot_system");
97
+ /**/
98
+ return;
99
+ }
100
+ /*
101
+ Extends the WP_Cron schedules to support 10 minute intervals.
102
+ Attach to: add_filter("cron_schedules");
103
+ */
104
+ function ws_plugin__s2member_extend_cron_schedules ($schedules = array ())
105
+ {
106
+ do_action ("s2member_before_extend_cron_schedules");
107
+ /**/
108
+ $array = array ("every10m" => array ("interval" => 600, "display" => "Every 10 Minutes"));
109
+ /**/
110
+ return apply_filters ("s2member_extend_cron_schedules", array_merge ($array, $schedules));
111
+ }
112
+ /*
113
+ Adds a scheduled task for s2Member's Auto-EOT System.
114
+ */
115
+ function ws_plugin__s2member_add_auto_eot_system ()
116
+ {
117
+ if (!ws_plugin__s2member_remove_auto_eot_system ())
118
+ {
119
+ return false; /* Do not proceed if unable to remove first. */
120
+ }
121
+ else /* Otherwise, we can safely schedule the event and return true. */
122
+ {
123
+ wp_schedule_event (time (), "every10m", "s2member_auto_eot_system");
124
+ /**/
125
+ return true;
126
+ }
127
+ }
128
+ /*
129
+ Remove scheduled tasks for s2Member's Auto-EOT System.
130
+ */
131
+ function ws_plugin__s2member_remove_auto_eot_system ()
132
+ {
133
+ wp_clear_scheduled_hook ("s2member_auto_eot_system");
134
+ /**/
135
+ return true;
136
+ }
137
+ ?>
includes/functions/catg-level-access.inc.php CHANGED
@@ -33,70 +33,74 @@ function ws_plugin__s2member_check_catg_level_access ()
33
  /**/
34
  if (is_category () && $cat_ID) /* We also check if this is a child category of a restricted category. */
35
  {
36
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
37
  exit;
38
  /**/
39
- else if (in_array ($cat_ID, ($level1_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_catgs"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
40
  exit;
41
  /**/
42
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=2")) !== "nill")
43
  exit;
44
  /**/
45
- else if (in_array ($cat_ID, ($level2_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_catgs"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=2")) !== "nill")
46
  exit;
47
  /**/
48
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=3")) !== "nill")
49
  exit;
50
  /**/
51
- else if (in_array ($cat_ID, ($level3_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_catgs"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=3")) !== "nill")
52
  exit;
53
  /**/
54
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=4")) !== "nill")
55
  exit;
56
  /**/
57
- else if (in_array ($cat_ID, ($level4_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_catgs"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=4")) !== "nill")
58
  exit;
59
  /**/
60
- foreach ($level1_catgs as $catg)
61
- if (cat_is_ancestor_of ($catg, $cat_ID) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
62
- exit;
 
63
  /**/
64
- foreach ($level2_catgs as $catg)
65
- if (cat_is_ancestor_of ($catg, $cat_ID) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=2")) !== "nill")
66
- exit;
 
67
  /**/
68
- foreach ($level3_catgs as $catg)
69
- if (cat_is_ancestor_of ($catg, $cat_ID) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=3")) !== "nill")
70
- exit;
 
71
  /**/
72
- foreach ($level4_catgs as $catg)
73
- if (cat_is_ancestor_of ($catg, $cat_ID) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=4")) !== "nill")
74
- exit;
 
75
  }
76
  else if (is_single () && !is_page () && $post_ID)
77
  {
78
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
79
  exit;
80
  /**/
81
- else if (($level1_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_catgs"])) && (in_category ($level1_catgs, $post_ID) || ws_plugin__s2member_in_descendant_category ($level1_catgs, $post_ID)) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
82
  exit;
83
  /**/
84
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=2")) !== "nill")
85
  exit;
86
  /**/
87
- else if (($level2_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_catgs"])) && (in_category ($level2_catgs, $post_ID) || ws_plugin__s2member_in_descendant_category ($level2_catgs, $post_ID)) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=2")) !== "nill")
88
  exit;
89
  /**/
90
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=3")) !== "nill")
91
  exit;
92
  /**/
93
- else if (($level3_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_catgs"])) && (in_category ($level3_catgs, $post_ID) || ws_plugin__s2member_in_descendant_category ($level3_catgs, $post_ID)) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=3")) !== "nill")
94
  exit;
95
  /**/
96
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=4")) !== "nill")
97
  exit;
98
  /**/
99
- else if (($level4_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_catgs"])) && (in_category ($level4_catgs, $post_ID) || ws_plugin__s2member_in_descendant_category ($level4_catgs, $post_ID)) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=4")) !== "nill")
100
  exit;
101
  }
102
  /**/
33
  /**/
34
  if (is_category () && $cat_ID) /* We also check if this is a child category of a restricted category. */
35
  {
36
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
37
  exit;
38
  /**/
39
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_catgs"] && in_array ($cat_ID, ($level1_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_catgs"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
40
  exit;
41
  /**/
42
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (add_query_arg ("s2member_level_req", "2", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
43
  exit;
44
  /**/
45
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_catgs"] && in_array ($cat_ID, ($level2_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_catgs"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (add_query_arg ("s2member_level_req", "2", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
46
  exit;
47
  /**/
48
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (add_query_arg ("s2member_level_req", "3", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
49
  exit;
50
  /**/
51
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_catgs"] && in_array ($cat_ID, ($level3_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_catgs"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (add_query_arg ("s2member_level_req", "3", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
52
  exit;
53
  /**/
54
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (add_query_arg ("s2member_level_req", "4", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
55
  exit;
56
  /**/
57
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_catgs"] && in_array ($cat_ID, ($level4_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_catgs"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (add_query_arg ("s2member_level_req", "4", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
58
  exit;
59
  /**/
60
+ if ($level1_catgs)
61
+ foreach ($level1_catgs as $catg)
62
+ if ($catg && cat_is_ancestor_of ($catg, $cat_ID) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
63
+ exit;
64
  /**/
65
+ if ($level2_catgs)
66
+ foreach ($level2_catgs as $catg)
67
+ if ($catg && cat_is_ancestor_of ($catg, $cat_ID) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (add_query_arg ("s2member_level_req", "2", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
68
+ exit;
69
  /**/
70
+ if ($level3_catgs)
71
+ foreach ($level3_catgs as $catg)
72
+ if ($catg && cat_is_ancestor_of ($catg, $cat_ID) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (add_query_arg ("s2member_level_req", "3", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
73
+ exit;
74
  /**/
75
+ if ($level4_catgs)
76
+ foreach ($level4_catgs as $catg)
77
+ if ($catg && cat_is_ancestor_of ($catg, $cat_ID) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (add_query_arg ("s2member_level_req", "4", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
78
+ exit;
79
  }
80
  else if (is_single () && !is_page () && $post_ID)
81
  {
82
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
83
  exit;
84
  /**/
85
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_catgs"] && (in_category (($level1_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_catgs"])), $post_ID) || ws_plugin__s2member_in_descendant_category ($level1_catgs, $post_ID)) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
86
  exit;
87
  /**/
88
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (add_query_arg ("s2member_level_req", "2", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
89
  exit;
90
  /**/
91
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_catgs"] && (in_category (($level2_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_catgs"])), $post_ID) || ws_plugin__s2member_in_descendant_category ($level2_catgs, $post_ID)) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (add_query_arg ("s2member_level_req", "2", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
92
  exit;
93
  /**/
94
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (add_query_arg ("s2member_level_req", "3", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
95
  exit;
96
  /**/
97
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_catgs"] && (in_category (($level3_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_catgs"])), $post_ID) || ws_plugin__s2member_in_descendant_category ($level3_catgs, $post_ID)) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (add_query_arg ("s2member_level_req", "3", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
98
  exit;
99
  /**/
100
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (add_query_arg ("s2member_level_req", "4", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
101
  exit;
102
  /**/
103
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_catgs"] && (in_category (($level4_catgs = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_catgs"])), $post_ID) || ws_plugin__s2member_in_descendant_category ($level4_catgs, $post_ID)) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (add_query_arg ("s2member_level_req", "4", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
104
  exit;
105
  }
106
  /**/
includes/functions/constants.inc.php CHANGED
@@ -29,6 +29,8 @@ function ws_plugin__s2member_constants ()
29
  $file_downloads = ws_plugin__s2member_user_downloads ("", $metas["s2member_file_download_access_log"]);
30
  $login_redirection_override = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_override"];
31
  /**/
 
 
32
  define ("S2MEMBER_CURRENT_USER_IS_LOGGED_IN", (($current_user) ? true : false)); /* This will always be (bool) true or false. False if they are NOT currently logged in. */
33
  define ("S2MEMBER_CURRENT_USER_IS_LOGGED_IN_AS_MEMBER", (($current_user && $level >= 1) ? true : false)); /* This will always be (bool) true or false. Level >= 1 for Members. */
34
  define ("S2MEMBER_CURRENT_USER_ACCESS_LEVEL", (int)$level); /* This will always be (int) negative 1 thru positive 4. -1 if user is not logged in. 0 if logged in as a Subscriber. */
@@ -90,8 +92,8 @@ function ws_plugin__s2member_constants ()
90
  define ("S2MEMBER_PAYPAL_ENDPOINT", (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")); /* Using sandbox? */
91
  define ("S2MEMBER_PAYPAL_BUSINESS", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"]); /* This is the email address that identifies your paypal business. */
92
  /**/
93
- define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0", ((S2MEMBER_CURRENT_USER_SUBSCR_ID) ? "Updating Subscr. ID" : "")); /* Auto-fills the on0 value in PayPal buttons. */
94
- define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS0", ((S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0) ? S2MEMBER_CURRENT_USER_SUBSCR_ID : "")); /* For the os0 value. */
95
  /**/
96
  do_action ("s2member_after_constants");
97
  /**/
29
  $file_downloads = ws_plugin__s2member_user_downloads ("", $metas["s2member_file_download_access_log"]);
30
  $login_redirection_override = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_override"];
31
  /**/
32
+ define ("S2MEMBER_VERSION", $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["version"]); /* Always a (string) containing the version. Available since 3.0. */
33
+ /**/
34
  define ("S2MEMBER_CURRENT_USER_IS_LOGGED_IN", (($current_user) ? true : false)); /* This will always be (bool) true or false. False if they are NOT currently logged in. */
35
  define ("S2MEMBER_CURRENT_USER_IS_LOGGED_IN_AS_MEMBER", (($current_user && $level >= 1) ? true : false)); /* This will always be (bool) true or false. Level >= 1 for Members. */
36
  define ("S2MEMBER_CURRENT_USER_ACCESS_LEVEL", (int)$level); /* This will always be (int) negative 1 thru positive 4. -1 if user is not logged in. 0 if logged in as a Subscriber. */
92
  define ("S2MEMBER_PAYPAL_ENDPOINT", (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")); /* Using sandbox? */
93
  define ("S2MEMBER_PAYPAL_BUSINESS", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"]); /* This is the email address that identifies your paypal business. */
94
  /**/
95
+ define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0", ((S2MEMBER_CURRENT_USER_SUBSCR_ID && !ws_plugin__s2member_user_has_wp_role ($current_user)) ? "Updating Subscr. ID" : ""));
96
+ define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS0", ((S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0) ? S2MEMBER_CURRENT_USER_SUBSCR_ID : "")); /* ^ Not for built-in WP Roles. */
97
  /**/
98
  do_action ("s2member_after_constants");
99
  /**/
includes/functions/file-download-access.inc.php CHANGED
@@ -135,7 +135,7 @@ function ws_plugin__s2member_check_file_download_access ()
135
  $file_download_access_is_allowed = $minimum_level_required_to_download_files = ws_plugin__s2member_min_level_4_downloads ();
136
  /**/
137
  if (!($current_user = (is_user_logged_in ()) ? wp_get_current_user () : false) /* Redirect Users who are not logged in. */
138
- && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=" . urlencode ($minimum_level_required_to_download_files) . "&s2member_file_download_req=" . urlencode ($_GET["s2member_file_download"]))) !== "nill")
139
  exit;
140
  /**/
141
  else if (!$file_download_access_is_allowed) /* Have file downloads even been enabled? */
@@ -153,7 +153,7 @@ function ws_plugin__s2member_check_file_download_access ()
153
  }
154
  /**/
155
  else if ((!is_array ($file_downloads = ws_plugin__s2member_user_downloads ()) || !$file_downloads["allowed"] || !$file_downloads["allowed_days"])/**/
156
- && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_limit_exceeded_page"]), "s2member_file_download_req=" . urlencode ($_GET["s2member_file_download"]))) !== "nill")
157
  exit;
158
  /**/
159
  $previous_file_downloads = 0; /* Here we're going to count how many downloads they've performed. */
@@ -178,7 +178,7 @@ function ws_plugin__s2member_check_file_download_access ()
178
  }
179
  /**/
180
  if (!$already_downloaded && $previous_file_downloads >= $file_downloads["allowed"] /* They have NOT already downloaded this file, and they're over their limit. */
181
- && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_limit_exceeded_page"]), "s2member_file_download_req=" . urlencode ($_GET["s2member_file_download"]))) !== "nill")
182
  exit;
183
  /**/
184
  if (!$already_downloaded) /* Only add this file to the log if they have not already downloaded it. */
135
  $file_download_access_is_allowed = $minimum_level_required_to_download_files = ws_plugin__s2member_min_level_4_downloads ();
136
  /**/
137
  if (!($current_user = (is_user_logged_in ()) ? wp_get_current_user () : false) /* Redirect Users who are not logged in. */
138
+ && wp_redirect (add_query_arg (array ("s2member_level_req" => $minimum_level_required_to_download_files, "s2member_file_download_req" => $_GET["s2member_file_download"]), get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
139
  exit;
140
  /**/
141
  else if (!$file_download_access_is_allowed) /* Have file downloads even been enabled? */
153
  }
154
  /**/
155
  else if ((!is_array ($file_downloads = ws_plugin__s2member_user_downloads ()) || !$file_downloads["allowed"] || !$file_downloads["allowed_days"])/**/
156
+ && wp_redirect (add_query_arg (array ("s2member_file_download_req" => $_GET["s2member_file_download"]), get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_limit_exceeded_page"]))) !== "nill")
157
  exit;
158
  /**/
159
  $previous_file_downloads = 0; /* Here we're going to count how many downloads they've performed. */
178
  }
179
  /**/
180
  if (!$already_downloaded && $previous_file_downloads >= $file_downloads["allowed"] /* They have NOT already downloaded this file, and they're over their limit. */
181
+ && wp_redirect (add_query_arg (array ("s2member_file_download_req" => $_GET["s2member_file_download"]), get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_limit_exceeded_page"]))) !== "nill")
182
  exit;
183
  /**/
184
  if (!$already_downloaded) /* Only add this file to the log if they have not already downloaded it. */
includes/functions/ip-restrictions.inc.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright: © 2009 WebSharks, Inc. ( coded in the USA )
4
+ <mailto:support@websharks-inc.com> <http://www.websharks-inc.com/>
5
+
6
+ Released under the terms of the GNU General Public License.
7
+ You should have received a copy of the GNU General Public License,
8
+ along with this software. In the main directory, see: /licensing/
9
+ If not, see: <http://www.gnu.org/licenses/>.
10
+ */
11
+ /*
12
+ Direct access denial.
13
+ */
14
+ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
+ exit;
16
+ /*
17
+ Function for handling IP Restrictions.
18
+ IP addresses are stored in a Transient field.
19
+ */
20
+ function ws_plugin__s2member_ip_restrictions_ok ($ip = FALSE, $restriction = FALSE)
21
+ {
22
+ do_action ("s2member_before_ip_restrictions_ok");
23
+ /**/
24
+ if ($restriction) /* There MUST be a restriction. However, the IP *can* be empty. */
25
+ {
26
+ if (is_array ($ips = get_transient ($transient = md5 ("s2member_ip_restrictions_" . $restriction))))
27
+ {
28
+ if (!in_array ($ip, $ips)) /* Already on record? */
29
+ $ips[] = $ip;
30
+ /**/
31
+ $new_ips = $ips;
32
+ }
33
+ else /* Otherwise, create a new IPs array. */
34
+ $new_ips[] = $ip;
35
+ /**/
36
+ if (count ($new_ips) > $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"])
37
+ {
38
+ ws_plugin__s2member_nocache_constants () . wp_clear_auth_cookie (); /* Clear cookies. */
39
+ /**/
40
+ do_action ("s2member_during_ip_restrictions_not_ok");
41
+ /**/
42
+ header ("HTTP/1.0 503 Service Temporarily Unavailable");
43
+ echo '<strong>503: Service Temporarily Unavailable</strong><br />' . "\n";
44
+ echo 'Too many IP addresses accessing one account/link!<br />' . "\n";
45
+ echo 'Please contact Support if you need assistance.';
46
+ /**/
47
+ exit; /* Exit now. */
48
+ }
49
+ else /* Otherwise, update the Transient array of IP addresses. They're good for now. */
50
+ {
51
+ do_action ("s2member_during_ip_restrictions_ok");
52
+ /**/
53
+ set_transient ($transient, $new_ips, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction_time"]);
54
+ /**/
55
+ return apply_filters ("s2member_ip_restrictions_ok", true);
56
+ }
57
+ }
58
+ /**/
59
+ return apply_filters ("s2member_ip_restrictions_ok", true);
60
+ }
61
+ ?>
includes/functions/js-globals.inc.php CHANGED
@@ -68,7 +68,9 @@ function ws_plugin__s2member_js_w_globals ()
68
  header ("Cache-Control: max-age=604800");
69
  header ("Pragma: public");
70
  /**/
71
- $g = "var S2MEMBER_CURRENT_USER_IS_LOGGED_IN = " . ((S2MEMBER_CURRENT_USER_IS_LOGGED_IN) ? "true" : "false") . ",";
 
 
72
  $g .= "S2MEMBER_CURRENT_USER_IS_LOGGED_IN_AS_MEMBER = " . ((S2MEMBER_CURRENT_USER_IS_LOGGED_IN_AS_MEMBER) ? "true" : "false") . ",";
73
  $g .= "S2MEMBER_CURRENT_USER_ACCESS_LEVEL = " . S2MEMBER_CURRENT_USER_ACCESS_LEVEL . ",";
74
  $g .= "S2MEMBER_CURRENT_USER_ACCESS_LABEL = '" . preg_replace ("/'/", "\'", S2MEMBER_CURRENT_USER_ACCESS_LABEL) . "',";
68
  header ("Cache-Control: max-age=604800");
69
  header ("Pragma: public");
70
  /**/
71
+ $g = "var S2MEMBER_VERSION = '" . preg_replace ("/'/", "\'", S2MEMBER_VERSION) . "',"; /* Since s2Member 3.0. */
72
+ /**/
73
+ $g .= "S2MEMBER_CURRENT_USER_IS_LOGGED_IN = " . ((S2MEMBER_CURRENT_USER_IS_LOGGED_IN) ? "true" : "false") . ",";
74
  $g .= "S2MEMBER_CURRENT_USER_IS_LOGGED_IN_AS_MEMBER = " . ((S2MEMBER_CURRENT_USER_IS_LOGGED_IN_AS_MEMBER) ? "true" : "false") . ",";
75
  $g .= "S2MEMBER_CURRENT_USER_ACCESS_LEVEL = " . S2MEMBER_CURRENT_USER_ACCESS_LEVEL . ",";
76
  $g .= "S2MEMBER_CURRENT_USER_ACCESS_LABEL = '" . preg_replace ("/'/", "\'", S2MEMBER_CURRENT_USER_ACCESS_LABEL) . "',";
includes/functions/list-servers.inc.php CHANGED
@@ -32,11 +32,11 @@ function ws_plugin__s2member_process_list_servers ($level = FALSE, $email = FALS
32
  $MCAPI->listSubscribe ($mailchimp_list_id, $email, array ("FNAME" => $fname, "LNAME" => $lname, "OPTINIP" => $ip));
33
  }
34
  /**/
35
- if ($aweber_list_ids = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $level . "_aweber_list_ids"])
36
  {
37
  foreach (preg_split ("/[\r\n\t\s;,]+/", $aweber_list_ids) as $aweber_list_id)
38
  @mail ($aweber_list_id . "@aweber.com", "s2Member Subscription Request",/**/
39
- "s2Member Subscription Request\ns2Member w/ PayPal Email ID\nBuyer: " . $fname . " " . $lname . "\n - end.",/**/
40
  "From: \"" . preg_replace ("/\"/", "", $fname . " " . $lname) . "\" <" . $email . ">\r\nContent-Type: text/plain; charset=utf-8");
41
  }
42
  }
32
  $MCAPI->listSubscribe ($mailchimp_list_id, $email, array ("FNAME" => $fname, "LNAME" => $lname, "OPTINIP" => $ip));
33
  }
34
  /**/
35
+ if (($aweber_list_ids = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $level . "_aweber_list_ids"]))
36
  {
37
  foreach (preg_split ("/[\r\n\t\s;,]+/", $aweber_list_ids) as $aweber_list_id)
38
  @mail ($aweber_list_id . "@aweber.com", "s2Member Subscription Request",/**/
39
+ "s2Member Subscription Request\ns2Member w/ PayPal Email ID\nEMail Address: " . $email . "\nBuyer: " . $fname . " " . $lname . "\nFull Name: " . $fname . " " . $lname . "\nFirst Name: " . $fname . "\nLast Name: " . $lname . "\nIP Address: " . $ip . "\nLevel: " . $level . "\n - end.",/**/
40
  "From: \"" . preg_replace ("/\"/", "", $fname . " " . $lname) . "\" <" . $email . ">\r\nContent-Type: text/plain; charset=utf-8");
41
  }
42
  }
includes/functions/login-redirection.inc.php CHANGED
@@ -27,12 +27,15 @@ function ws_plugin__s2member_login_redirect ($username = FALSE)
27
  {
28
  do_action ("s2member_during_login_redirect"); /* Custom redirections. */
29
  /**/
30
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_override"])
31
- wp_redirect (ws_plugin__s2member_fill_login_redirect_rc_vars /* Special. */
32
- ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_override"], $user));
33
- /**/
34
- else /* Otherwise, use the Login Welcome Page for s2Member. */
35
- wp_redirect (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"]));
 
 
 
36
  /**/
37
  exit;
38
  }
27
  {
28
  do_action ("s2member_during_login_redirect"); /* Custom redirections. */
29
  /**/
30
+ if (ws_plugin__s2member_ip_restrictions_ok ($_SERVER["REMOTE_ADDR"], strtolower ($username)))
31
+ {
32
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_override"])
33
+ wp_redirect (ws_plugin__s2member_fill_login_redirect_rc_vars /* Special. */
34
+ ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_override"], $user));
35
+ /**/
36
+ else /* Otherwise, use the Login Welcome Page for s2Member. */
37
+ wp_redirect (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"]));
38
+ }
39
  /**/
40
  exit;
41
  }
includes/functions/menu-pages.inc.php CHANGED
@@ -48,8 +48,12 @@ function ws_plugin__s2member_update_all_options ()
48
  /**/
49
  update_option ("ws_plugin__s2member_options", $options) . update_option ("ws_plugin__s2member_cache", array ());
50
  /**/
 
 
 
 
 
51
  do_action ("s2member_during_update_all_options"); /* Purposely after the update. */
52
- /* If you need to save custom options, please save them into a separate option key of your own. */
53
  /**/
54
  ws_plugin__s2member_display_admin_notice ('<strong>Options saved.</strong>'); /* Display admin notice. */
55
  }
@@ -226,12 +230,12 @@ function ws_plugin__s2member_paypal_ops_page ()
226
  $logs_dir = $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["logs_dir"];
227
  /**/
228
  if (!is_dir ($logs_dir) && is_writable (dirname ($logs_dir)))
229
- mkdir ($logs_dir, 0777);
230
  /**/
231
  $htaccess = $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["logs_dir"] . "/.htaccess";
232
  /**/
233
  if (is_dir ($logs_dir) && is_writable ($logs_dir) && !file_exists ($htaccess))
234
- file_put_contents ($htaccess, "deny from all");
235
  /**/
236
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_debug"]) /* If logging is enabled. */
237
  {
@@ -266,12 +270,12 @@ function ws_plugin__s2member_down_ops_page ()
266
  $files_dir = $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"];
267
  /**/
268
  if (!is_dir ($files_dir) && is_writable (dirname ($files_dir)))
269
- mkdir ($files_dir, 0777);
270
  /**/
271
  $htaccess = $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"] . "/.htaccess";
272
  /**/
273
  if (is_dir ($files_dir) && is_writable ($files_dir) && !file_exists ($htaccess))
274
- file_put_contents ($htaccess, "deny from all");
275
  /**/
276
  if (!is_dir ($files_dir)) /* If the security-enabled files directory does not exist yet. */
277
  ws_plugin__s2member_display_admin_notice ("The security-enabled files directory ( <code>" . preg_replace ("/^" . preg_quote ($_SERVER["DOCUMENT_ROOT"], "/") . "/", "", $files_dir) . "</code> ) does not exist. Please create this directory manually.", true);
48
  /**/
49
  update_option ("ws_plugin__s2member_options", $options) . update_option ("ws_plugin__s2member_cache", array ());
50
  /**/
51
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["auto_eot_system_enabled"])
52
+ ws_plugin__s2member_add_auto_eot_system (); /* Uses WP_Cron. */
53
+ else /* Otherwise, the Auto-EOT System needs to be disabled. */
54
+ ws_plugin__s2member_remove_auto_eot_system ();
55
+ /**/
56
  do_action ("s2member_during_update_all_options"); /* Purposely after the update. */
 
57
  /**/
58
  ws_plugin__s2member_display_admin_notice ('<strong>Options saved.</strong>'); /* Display admin notice. */
59
  }
230
  $logs_dir = $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["logs_dir"];
231
  /**/
232
  if (!is_dir ($logs_dir) && is_writable (dirname ($logs_dir)))
233
+ mkdir ($logs_dir, 0777) . clearstatcache ();
234
  /**/
235
  $htaccess = $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["logs_dir"] . "/.htaccess";
236
  /**/
237
  if (is_dir ($logs_dir) && is_writable ($logs_dir) && !file_exists ($htaccess))
238
+ file_put_contents ($htaccess, "deny from all") . clearstatcache ();
239
  /**/
240
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_debug"]) /* If logging is enabled. */
241
  {
270
  $files_dir = $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"];
271
  /**/
272
  if (!is_dir ($files_dir) && is_writable (dirname ($files_dir)))
273
+ mkdir ($files_dir, 0777) . clearstatcache ();
274
  /**/
275
  $htaccess = $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"] . "/.htaccess";
276
  /**/
277
  if (is_dir ($files_dir) && is_writable ($files_dir) && !file_exists ($htaccess))
278
+ file_put_contents ($htaccess, "deny from all") . clearstatcache ();
279
  /**/
280
  if (!is_dir ($files_dir)) /* If the security-enabled files directory does not exist yet. */
281
  ws_plugin__s2member_display_admin_notice ("The security-enabled files directory ( <code>" . preg_replace ("/^" . preg_quote ($_SERVER["DOCUMENT_ROOT"], "/") . "/", "", $files_dir) . "</code> ) does not exist. Please create this directory manually.", true);
includes/functions/nocache.inc.php CHANGED
@@ -50,6 +50,7 @@ These additional supplemental routines, include:
50
  - ws_plugin__s2member_check_ptag_level_access()
51
  - ws_plugin__s2member_check_post_level_access()
52
  - ws_plugin__s2member_check_page_level_access()
 
53
  */
54
  function ws_plugin__s2member_nocache_constants ($nocache = FALSE) /* Always obey the Quick Cache plugin. */
55
  {
50
  - ws_plugin__s2member_check_ptag_level_access()
51
  - ws_plugin__s2member_check_post_level_access()
52
  - ws_plugin__s2member_check_page_level_access()
53
+ - ws_plugin__s2member_ip_restrictions_ok()
54
  */
55
  function ws_plugin__s2member_nocache_constants ($nocache = FALSE) /* Always obey the Quick Cache plugin. */
56
  {
includes/functions/page-level-access.inc.php CHANGED
@@ -14,7 +14,7 @@ Direct access denial.
14
  if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
  exit;
16
  /*
17
- Function for handling page level access permissions.
18
  Attach to: add_action("template_redirect");
19
  */
20
  function ws_plugin__s2member_check_page_level_access ()
@@ -29,37 +29,37 @@ function ws_plugin__s2member_check_page_level_access ()
29
  {
30
  $current_user = (is_user_logged_in ()) ? wp_get_current_user () : false;
31
  /**/
32
- if ($page_ID == $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"] && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || (!current_user_can ("access_s2member_level1") && !$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["allow_subscribers_in"])) && $page_ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"] && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
33
  exit;
34
  /**/
35
- else if ($page_ID == $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_limit_exceeded_page"] && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && $page_ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"] && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
36
  exit;
37
  /**/
38
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_pages"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
39
  exit;
40
  /**/
41
- else if (in_array ($page_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_pages"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
42
  exit;
43
  /**/
44
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_pages"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=2")) !== "nill")
45
  exit;
46
  /**/
47
- else if (in_array ($page_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_pages"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=2")) !== "nill")
48
  exit;
49
  /**/
50
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_pages"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=3")) !== "nill")
51
  exit;
52
  /**/
53
- else if (in_array ($page_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_pages"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=3")) !== "nill")
54
  exit;
55
  /**/
56
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_pages"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=4")) !== "nill")
57
  exit;
58
  /**/
59
- else if (in_array ($page_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_pages"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=4")) !== "nill")
60
  exit;
61
  /**/
62
- else if (in_array ($page_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["single_pages"])) && ws_plugin__s2member_nocache_constants () !== "nill" && !ws_plugin__s2member_sp_access ($page_ID) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_sp_req=" . urlencode ($page_ID))) !== "nill")
63
  exit;
64
  /**/
65
  do_action ("s2member_during_check_page_level_access");
14
  if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
  exit;
16
  /*
17
+ Function for handling Page Level Access permissions.
18
  Attach to: add_action("template_redirect");
19
  */
20
  function ws_plugin__s2member_check_page_level_access ()
29
  {
30
  $current_user = (is_user_logged_in ()) ? wp_get_current_user () : false;
31
  /**/
32
+ if ($page_ID == $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"] && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || (!current_user_can ("access_s2member_level1") && !$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["allow_subscribers_in"])) && $page_ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"] && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
33
  exit;
34
  /**/
35
+ else if ($page_ID == $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_limit_exceeded_page"] && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && $page_ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"] && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
36
  exit;
37
  /**/
38
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_pages"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
39
  exit;
40
  /**/
41
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_pages"] && in_array ($page_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_pages"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
42
  exit;
43
  /**/
44
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_pages"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (add_query_arg ("s2member_level_req", "2", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
45
  exit;
46
  /**/
47
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_pages"] && in_array ($page_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_pages"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (add_query_arg ("s2member_level_req", "2", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
48
  exit;
49
  /**/
50
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_pages"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (add_query_arg ("s2member_level_req", "3", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
51
  exit;
52
  /**/
53
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_pages"] && in_array ($page_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_pages"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (add_query_arg ("s2member_level_req", "3", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
54
  exit;
55
  /**/
56
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_pages"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (add_query_arg ("s2member_level_req", "4", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
57
  exit;
58
  /**/
59
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_pages"] && in_array ($page_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_pages"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (add_query_arg ("s2member_level_req", "4", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
60
  exit;
61
  /**/
62
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["specific_ids"] && in_array ($page_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["specific_ids"])) && ws_plugin__s2member_nocache_constants () !== "nill" && !ws_plugin__s2member_sp_access ($page_ID) && !ws_plugin__s2member_is_systematic_use_page () && wp_redirect (add_query_arg ("s2member_sp_req", $page_ID, get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
63
  exit;
64
  /**/
65
  do_action ("s2member_during_check_page_level_access");
includes/functions/paypal-notify.inc.php CHANGED
@@ -14,43 +14,51 @@ Direct access denial.
14
  if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
  exit;
16
  /*
17
- Handles paypal ipn url processing.
18
  Attach to: add_action("init");
19
  */
20
  function ws_plugin__s2member_paypal_notify ()
21
  {
22
  do_action ("s2member_before_paypal_notify");
23
  /**/
 
 
24
  if ($_GET["s2member_paypal_notify"] && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"])
25
  {
26
- global $wpdb; /* Need this global variable as a reference to the database object. */
27
- /**/
28
- if (is_object ($wpdb) && is_array ($paypal = ws_plugin__s2member_paypal_postvars ()))
29
  {
 
30
  $paypal["s2member_log"][] = "s2Member POST vars verified through a POST back to PayPal®.";
31
  /**/
 
 
 
 
 
32
  if (preg_match ("/^" . preg_quote ($_SERVER["HTTP_HOST"], "/") . "/i", $paypal["custom"])) /* Matches originating host? */
33
  { /* The business address validation was removed from this routine, because PayPal® always fills that with the primary
34
- email address. In cases where an alternate PayPal® address is being paid, validation is not possible. */
35
  $paypal["s2member_log"][] = "s2Member originating domain ( _SERVER[HTTP_HOST] ) validated.";
36
  /*
37
- Single-Page Access.
38
  */
39
- if (preg_match ("/^web_accept$/i", $paypal["txn_type"]) && $paypal["payer_email"] && $paypal["txn_id"] && preg_match ("/^sp\:[0-9]+\:[0-9]+$/", $paypal["item_number"]))
40
  {
41
  do_action ("s2member_during_paypal_notify_before_sp_access");
42
  /**/
43
- $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept) for Single-Page access.";
44
  /**/
45
- list (, $paypal["page"], $paypal["hours"]) = preg_split ("/\:/", $paypal["item_number"], 3);
46
  /**/
47
- if (($sp_access_url = ws_plugin__s2member_sp_access_link_gen ($paypal["page"], $paypal["hours"])) && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
48
  {
49
- $sbj = preg_replace ("/%%sp_access_url%%/i", $sp_access_url, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["single_page_email_subject"]);
50
- $sbj = preg_replace ("/%%sp_access_exp%%/i", human_time_diff (strtotime ("now"), strtotime ("+" . $paypal["hours"] . " hours")), $sbj);
 
 
51
  /**/
52
- $msg = preg_replace ("/%%sp_access_url%%/i", $sp_access_url, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["single_page_email_message"]);
53
- $msg = preg_replace ("/%%sp_access_exp%%/i", human_time_diff (strtotime ("now"), strtotime ("+" . $paypal["hours"] . " hours")), $msg);
54
  /**/
55
  if (($sbj = preg_replace ("/%%cv([0-9]+)%%/ei", 'trim($cv[$1])', $sbj)) && ($sbj = preg_replace ("/%%txn_id%%/i", $paypal["txn_id"], $sbj)))
56
  if (($sbj = preg_replace ("/%%amount%%/i", $paypal["mc_gross"], $sbj))) /* Full amount of the payment, before fee is subtracted. */
@@ -70,15 +78,15 @@ function ws_plugin__s2member_paypal_notify ()
70
  {
71
  @mail ($paypal["payer_email"], $sbj, $msg, "From: \"" . preg_replace ('/"/', "'", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_name"]) . "\" <" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"] . ">\r\nContent-Type: text/plain; charset=utf-8");
72
  /**/
73
- $paypal["s2member_log"][] = "Single-Page Confirmation Email sent to Customer, with a URL that provides Single-Page Access.";
74
  }
75
  /**/
76
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_notification_urls"])
77
  {
78
  foreach (preg_split ("/[\r\n\t]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_notification_urls"]) as $url)
79
  /**/
80
  if (($url = preg_replace ("/%%cv([0-9]+)%%/ei", 'urlencode(trim($cv[$1]))', $url)) && ($url = preg_replace ("/%%sp_access_url%%/i", rawurlencode ($sp_access_url), $url)))
81
- if (($url = preg_replace ("/%%sp_access_exp%%/i", urlencode (human_time_diff (strtotime ("now"), strtotime ("+" . $paypal["hours"] . " hours"))), $url)))
82
  if (($url = preg_replace ("/%%amount%%/i", urlencode ($paypal["mc_gross"]), $url)) && ($url = preg_replace ("/%%txn_id%%/i", urlencode ($paypal["txn_id"]), $url)))
83
  if (($url = preg_replace ("/%%item_number%%/i", urlencode ($paypal["item_number"]), $url)) && ($url = preg_replace ("/%%item_name%%/i", urlencode ($paypal["item_name"]), $url)))
84
  if (($url = preg_replace ("/%%first_name%%/i", urlencode ($paypal["first_name"]), $url)) && ($url = preg_replace ("/%%last_name%%/i", urlencode ($paypal["last_name"]), $url)))
@@ -88,42 +96,75 @@ function ws_plugin__s2member_paypal_notify ()
88
  if (($url = trim ($url))) /* Make sure it is not empty. */
89
  ws_plugin__s2member_curlpsr ($url, "s2member=1");
90
  /**/
91
- $paypal["s2member_log"][] = "Payment Notification URLs have been processed.";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  }
93
  /**/
94
  do_action ("s2member_during_paypal_notify_during_sp_access");
95
  }
 
 
 
 
96
  /**/
97
  do_action ("s2member_during_paypal_notify_after_sp_access");
98
  }
99
  /*
100
- New subscriptions. Possibly containing advanced updated vars ( option_name1, option_selection1 ); which allow account modifications.
101
  */
102
- else if (preg_match ("/^(web_accept|subscr_signup)$/i", $paypal["txn_type"]) && $paypal["payer_email"] && ($paypal["subscr_id"] || ($paypal["subscr_id"] = $paypal["txn_id"])) && preg_match ("/^[1-4](\:|$)/", $paypal["item_number"]))
103
  {
104
  do_action ("s2member_during_paypal_notify_before_subscr_signup");
105
  /**/
106
  $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept|subscr_signup).";
107
  /**/
108
- list ($paypal["level"], $paypal["ccaps"]) = preg_split ("/\:/", $paypal["item_number"], 2);
 
 
 
 
 
 
 
 
 
 
 
 
109
  /*
110
- New subscription with advanced update vars ( option_name1, option_selection1 ).
111
  */
112
- if (preg_match ("/(updat|upgrad)/i", $paypal["option_name1"]) && $paypal["option_selection1"]) /* This is an advanced way to handle subscription update modifications. */
113
- /* This advanced method is required whenever a subscription that is already completed, or was never setup to recur in the first place needs to be modified. PayPal will not allow the
114
- modify=1|2 parameter to be used in those scenarios, because technically there is nothing to update. The only thing that actually needs to be updated is their existing account. */
115
  {
116
  do_action ("s2member_during_paypal_notify_before_subscr_signup_w_update_vars");
117
  /**/
118
  $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept|subscr_signup) w/ update vars.";
119
  /**/
120
- /* Here we need to check for both the old & new s2member_subscr_id's, just in case the Return routine has already changed it. */
121
- if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = 's2member_subscr_id' AND (`meta_value` = '" . $wpdb->escape ($paypal["option_selection1"]) . "' OR `meta_value` = '" . $wpdb->escape ($paypal["subscr_id"]) . "') LIMIT 1"))/**/
122
- || ($q = $wpdb->get_row ("SELECT `ID` AS `user_id` FROM `" . $wpdb->users . "` WHERE `ID` = '" . $wpdb->escape ($paypal["option_selection1"]) . "' LIMIT 1")))
123
  {
124
- if ($user_id = $q->user_id) /* Got it! */
 
 
125
  {
126
- $user = new WP_User ($user_id);
 
127
  $user->set_role ("s2member_level" . $paypal["level"]);
128
  update_usermeta ($user_id, "s2member_subscr_id", $paypal["subscr_id"]);
129
  update_usermeta ($user_id, "s2member_custom", $paypal["custom"]);
@@ -139,6 +180,13 @@ function ws_plugin__s2member_paypal_notify ()
139
  delete_usermeta ($user_id, "s2member_file_download_access_arc");
140
  delete_usermeta ($user_id, "s2member_file_download_access_log");
141
  /**/
 
 
 
 
 
 
 
142
  $paypal["s2member_log"][] = "s2Member Level/Capabilities updated w/ advanced update routines.";
143
  /**/
144
  @mail ($paypal["payer_email"], "Thank You! Your membership has been updated.", "Thank You! Your membership has been updated to:\n" . $paypal["item_name"] . "\n\nYou\\'ll need to log back in now.\n" . wp_login_url (), "From: \"" . preg_replace ('/"/', "'", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_name"]) . "\" <" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"] . ">\r\nContent-Type: text/plain; charset=utf-8");
@@ -149,20 +197,20 @@ function ws_plugin__s2member_paypal_notify ()
149
  }
150
  else
151
  {
152
- $paypal["s2member_log"][] = "Unable to modify subscription. Could not get the existing user_id from the DB. Please check the on0 and os0 variables in your Button Code.";
153
  }
154
  }
155
  else
156
  {
157
- $paypal["s2member_log"][] = "Unable to modify subscription. Could not find existing subscription in the DB. Please check the on0 and os0 variables in your Button Code.";
158
  }
159
  /**/
160
  do_action ("s2member_during_paypal_notify_after_subscr_signup_w_update_vars");
161
  }
162
  /*
163
- New subscription. Normal subscription signup, we are not updating anything for a past subscription.
164
  */
165
- else /* Else this is a normal subscription signup, we are not updating anything for a past subscription. */
166
  {
167
  do_action ("s2member_during_paypal_notify_before_subscr_signup_wo_update_vars");
168
  /**/
@@ -170,32 +218,22 @@ function ws_plugin__s2member_paypal_notify ()
170
  /**/
171
  if (($registration_url = ws_plugin__s2member_register_link_gen ($paypal["subscr_id"], $paypal["custom"], $paypal["item_number"])) && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
172
  {
 
 
173
  $sbj = preg_replace ("/%%registration_url%%/i", $registration_url, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_email_subject"]);
174
  $msg = preg_replace ("/%%registration_url%%/i", $registration_url, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_email_message"]);
175
  /**/
176
- if (preg_match ("/^web_accept$/i", $paypal["txn_type"]))
177
- {
178
- $paypal["period3"] = "1 L"; /* 1 Lifetime. */
179
- $paypal["mc_amount3"] = $paypal["mc_gross"];
180
- }
181
- /**/
182
- $initial_term = $paypal["period1"] ? $paypal["period1"] : "0 D"; /* Do not allow the initial period to be empty. Defaults to 0 D. */
183
- $initial = (isset ($paypal["mc_amount1"]) && preg_match ("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
184
- $regular = $paypal["mc_amount3"]; /* This is the regular payment amount that is charged to the customer. Always required by PayPal. */
185
- $recurring = ($paypal["recurring"]) ? $paypal["mc_amount3"] : "0"; /* If non-recurring, this should be zero, otherwise regular. */
186
- /* The initial amount will only be $0 if a trial was offered. If no trial was offered, they were charged a regular rate. */
187
- /**/
188
  if (($sbj = preg_replace ("/%%cv([0-9]+)%%/ei", 'trim($cv[$1])', $sbj)) && ($sbj = preg_replace ("/%%subscr_id%%/i", $paypal["subscr_id"], $sbj)))
189
- if (($sbj = preg_replace ("/%%initial%%/i", $initial, $sbj)) && ($sbj = preg_replace ("/%%recurring%%/i", $recurring, $sbj)) && ($sbj = preg_replace ("/%%regular%%/i", $regular, $sbj)))
190
- if (($sbj = preg_replace ("/%%initial_term%%/i", $initial_term, $sbj)) && ($sbj = preg_replace ("/%%regular_term%%/i", $paypal["period3"], $sbj)))
191
  if (($sbj = preg_replace ("/%%item_number%%/i", $paypal["item_number"], $sbj)) && ($sbj = preg_replace ("/%%item_name%%/i", $paypal["item_name"], $sbj)))
192
  if (($sbj = preg_replace ("/%%first_name%%/i", $paypal["first_name"], $sbj)) && ($sbj = preg_replace ("/%%last_name%%/i", $paypal["last_name"], $sbj)))
193
  if (($sbj = preg_replace ("/%%full_name%%/i", trim ($paypal["first_name"] . " " . $paypal["last_name"]), $sbj)))
194
  if (($sbj = preg_replace ("/%%payer_email%%/i", $paypal["payer_email"], $sbj)))
195
  /**/
196
  if (($msg = preg_replace ("/%%cv([0-9]+)%%/ei", 'trim($cv[$1])', $msg)) && ($msg = preg_replace ("/%%subscr_id%%/i", $paypal["subscr_id"], $msg)))
197
- if (($msg = preg_replace ("/%%initial%%/i", $initial, $msg)) && ($msg = preg_replace ("/%%recurring%%/i", $recurring, $msg)) && ($msg = preg_replace ("/%%regular%%/i", $regular, $msg)))
198
- if (($msg = preg_replace ("/%%initial_term%%/i", $initial_term, $msg)) && ($msg = preg_replace ("/%%regular_term%%/i", $paypal["period3"], $msg)))
199
  if (($msg = preg_replace ("/%%item_number%%/i", $paypal["item_number"], $msg)) && ($msg = preg_replace ("/%%item_name%%/i", $paypal["item_name"], $msg)))
200
  if (($msg = preg_replace ("/%%first_name%%/i", $paypal["first_name"], $msg)) && ($msg = preg_replace ("/%%last_name%%/i", $paypal["last_name"], $msg)))
201
  if (($msg = preg_replace ("/%%full_name%%/i", trim ($paypal["first_name"] . " " . $paypal["last_name"]), $msg)))
@@ -214,25 +252,13 @@ function ws_plugin__s2member_paypal_notify ()
214
  do_action ("s2member_during_paypal_notify_after_subscr_signup_wo_update_vars");
215
  }
216
  /**/
217
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_notification_urls"] && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
218
  {
219
- if (preg_match ("/^web_accept$/i", $paypal["txn_type"]))
220
- {
221
- $paypal["period3"] = "1 L"; /* 1 Lifetime. */
222
- $paypal["mc_amount3"] = $paypal["mc_gross"];
223
- }
224
- /**/
225
- $initial_term = $paypal["period1"] ? $paypal["period1"] : "0 D"; /* Do not allow the initial period to be empty. Defaults to 0 D. */
226
- $initial = (isset ($paypal["mc_amount1"]) && preg_match ("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
227
- $regular = $paypal["mc_amount3"]; /* This is the regular payment amount that is charged to the customer. Always required by PayPal. */
228
- $recurring = ($paypal["recurring"]) ? $paypal["mc_amount3"] : "0"; /* If non-recurring, this should be zero, otherwise regular. */
229
- /* The initial amount will only be $0 if a trial was offered. If no trial was offered, they were charged a regular rate. */
230
- /**/
231
  foreach (preg_split ("/[\r\n\t]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_notification_urls"]) as $url)
232
  /**/
233
  if (($url = preg_replace ("/%%cv([0-9]+)%%/ei", 'urlencode(trim($cv[$1]))', $url)) && ($url = preg_replace ("/%%subscr_id%%/i", urlencode ($paypal["subscr_id"]), $url)))
234
- if (($url = preg_replace ("/%%initial%%/i", urlencode ($initial), $url)) && ($url = preg_replace ("/%%recurring%%/i", urlencode ($recurring), $url)) && ($url = preg_replace ("/%%regular%%/i", urlencode ($regular), $url)))
235
- if (($url = preg_replace ("/%%initial_term%%/i", urlencode ($initial_term), $url)) && ($url = preg_replace ("/%%regular_term%%/i", urlencode ($paypal["period3"]), $url)))
236
  if (($url = preg_replace ("/%%item_number%%/i", urlencode ($paypal["item_number"]), $url)) && ($url = preg_replace ("/%%item_name%%/i", urlencode ($paypal["item_name"]), $url)))
237
  if (($url = preg_replace ("/%%first_name%%/i", urlencode ($paypal["first_name"]), $url)) && ($url = preg_replace ("/%%last_name%%/i", urlencode ($paypal["last_name"]), $url)))
238
  if (($url = preg_replace ("/%%full_name%%/i", urlencode (trim ($paypal["first_name"] . " " . $paypal["last_name"])), $url)))
@@ -244,12 +270,46 @@ function ws_plugin__s2member_paypal_notify ()
244
  $paypal["s2member_log"][] = "Signup Notification URLs have been processed.";
245
  }
246
  /**/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  do_action ("s2member_during_paypal_notify_after_subscr_signup");
248
  }
249
  /*
250
  Subscription modifications.
251
  */
252
- else if (preg_match ("/^subscr_modify$/i", $paypal["txn_type"]) && $paypal["subscr_id"] && preg_match ("/^[1-4](\:|$)/", $paypal["item_number"]))
253
  {
254
  do_action ("s2member_during_paypal_notify_before_subscr_modify");
255
  /**/
@@ -257,11 +317,14 @@ function ws_plugin__s2member_paypal_notify ()
257
  /**/
258
  list ($paypal["level"], $paypal["ccaps"]) = preg_split ("/\:/", $paypal["item_number"], 2);
259
  /**/
260
- if ($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = 's2member_subscr_id' AND `meta_value` = '" . $wpdb->escape ($paypal["subscr_id"]) . "' LIMIT 1"))
261
  {
262
- if ($user_id = $q->user_id) /* Got it! */
 
 
263
  {
264
- $user = new WP_User ($user_id);
 
265
  $user->set_role ("s2member_level" . $paypal["level"]);
266
  update_usermeta ($user_id, "s2member_subscr_id", $paypal["subscr_id"]);
267
  update_usermeta ($user_id, "s2member_custom", $paypal["custom"]);
@@ -276,8 +339,11 @@ function ws_plugin__s2member_paypal_notify ()
276
  /**/
277
  delete_usermeta ($user_id, "s2member_file_download_access_arc");
278
  delete_usermeta ($user_id, "s2member_file_download_access_log");
 
279
  /**/
280
- $paypal["s2member_log"][] = "s2Member Level/Capabilities updated on subscription modification.";
 
 
281
  /**/
282
  @mail ($paypal["payer_email"], "Thank You! Your membership has been updated.", "Thank You! Your membership has been updated to:\n" . $paypal["item_name"] . "\n\nYou\\'ll need to log back in now.\n" . wp_login_url (), "From: \"" . preg_replace ('/"/', "'", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_name"]) . "\" <" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"] . ">\r\nContent-Type: text/plain; charset=utf-8");
283
  /**/
@@ -287,12 +353,12 @@ function ws_plugin__s2member_paypal_notify ()
287
  }
288
  else
289
  {
290
- $paypal["s2member_log"][] = "Unable to modify subscription. Could not get the existing user_id from the DB.";
291
  }
292
  }
293
  else
294
  {
295
- $paypal["s2member_log"][] = "Unable to modify subscription. Could not find existing subscription in the DB.";
296
  }
297
  /**/
298
  do_action ("s2member_during_paypal_notify_after_subscr_modify");
@@ -300,123 +366,223 @@ function ws_plugin__s2member_paypal_notify ()
300
  /*
301
  Subscription payments.
302
  */
303
- else if (preg_match ("/^subscr_payment$/i", $paypal["txn_type"]) && $paypal["payer_email"] && $paypal["subscr_id"] && preg_match ("/^[1-4](\:|$)/", $paypal["item_number"]) && $paypal["txn_id"] && $paypal["mc_gross"])
304
  {
305
  do_action ("s2member_during_paypal_notify_before_subscr_payment");
306
  /**/
307
  $paypal["s2member_log"][] = "s2Member txn_type identified as subscr_payment.";
 
 
 
 
308
  /**/
309
  list ($paypal["level"], $paypal["ccaps"]) = preg_split ("/\:/", $paypal["item_number"], 2);
310
  /**/
311
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["payment_notification_urls"] && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
312
  {
313
- foreach (preg_split ("/[\r\n\t]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["payment_notification_urls"]) as $url)
314
- /**/
315
- if (($url = preg_replace ("/%%cv([0-9]+)%%/ei", 'urlencode(trim($cv[$1]))', $url)) && ($url = preg_replace ("/%%subscr_id%%/i", urlencode ($paypal["subscr_id"]), $url)))
316
- if (($url = preg_replace ("/%%amount%%/i", urlencode ($paypal["mc_gross"]), $url)) && ($url = preg_replace ("/%%txn_id%%/i", urlencode ($paypal["txn_id"]), $url)))
317
- if (($url = preg_replace ("/%%item_number%%/i", urlencode ($paypal["item_number"]), $url)) && ($url = preg_replace ("/%%item_name%%/i", urlencode ($paypal["item_name"]), $url)))
318
- if (($url = preg_replace ("/%%first_name%%/i", urlencode ($paypal["first_name"]), $url)) && ($url = preg_replace ("/%%last_name%%/i", urlencode ($paypal["last_name"]), $url)))
319
- if (($url = preg_replace ("/%%full_name%%/i", urlencode (trim ($paypal["first_name"] . " " . $paypal["last_name"])), $url)))
320
- if (($url = preg_replace ("/%%payer_email%%/i", urlencode ($paypal["payer_email"]), $url)))
321
- /**/
322
- if (($url = trim ($url))) /* Make sure it is not empty. */
323
- ws_plugin__s2member_curlpsr ($url, "s2member=1");
324
  /**/
325
- $paypal["s2member_log"][] = "Payment Notification URLs have been processed.";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
326
  }
327
  /**/
328
  do_action ("s2member_during_paypal_notify_after_subscr_payment");
329
  }
330
  /*
331
- Subscription terminations.
 
 
 
332
  */
333
- else if ((preg_match ("/^subscr_eot$/i", $paypal["txn_type"]) || preg_match ("/^(refunded|reversed)$/i", $paypal["payment_status"])) && ($paypal["subscr_id"] || ($paypal["subscr_id"] = $paypal["parent_txn_id"])) && preg_match ("/^[1-4](\:|$)/", $paypal["item_number"]))
334
  {
335
- do_action ("s2member_during_paypal_notify_before_subscr_eot");
336
  /**/
337
- $paypal["s2member_log"][] = "s2Member txn_type identified as subscr_eot - or - payment_status (refunded|reversed).";
338
  /**/
339
  list ($paypal["level"], $paypal["ccaps"]) = preg_split ("/\:/", $paypal["item_number"], 2);
340
  /**/
341
- if ($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = 's2member_subscr_id' AND `meta_value` = '" . $wpdb->escape ($paypal["subscr_id"]) . "' LIMIT 1"))
342
  {
343
- if ($user_id = $q->user_id) /* Demote to Free Subscriber, or delete the Member completely. */
 
 
 
 
 
 
 
 
 
 
 
 
344
  {
345
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_eot_behavior"] === "demote")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
  {
347
- $user = new WP_User ($user_id);
348
- $user->set_role ("subscriber");
349
- delete_usermeta ($user_id, "s2member_custom");
350
- delete_usermeta ($user_id, "s2member_subscr_id");
351
- /**/
352
- foreach ($user->allcaps as $cap => $cap_enabled)
353
- if (preg_match ("/^access_s2member_ccap_/", $cap))
354
- $user->remove_cap ($ccap = $cap);
355
- /**/
356
- delete_usermeta ($user_id, "s2member_file_download_access_arc");
357
- delete_usermeta ($user_id, "s2member_file_download_access_log");
358
- /**/
359
- $paypal["s2member_log"][] = "Member Level/Capabilities demoted to a Free Subscriber.";
360
- /**/
361
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_del_notification_urls"] && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
362
  {
363
- foreach (preg_split ("/[\r\n\t]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_del_notification_urls"]) as $url) /* Handle eot notifications. */
364
- /**/
365
- if (($url = preg_replace ("/%%cv([0-9]+)%%/ei", 'urlencode(trim($cv[$1]))', $url)) && ($url = preg_replace ("/%%subscr_id%%/i", urlencode ($paypal["subscr_id"]), $url)))
366
- if (($url = preg_replace ("/%%user_first_name%%/i", urlencode ($user->first_name), $url)) && ($url = preg_replace ("/%%user_last_name%%/i", urlencode ($user->last_name), $url)))
367
- if (($url = preg_replace ("/%%user_full_name%%/i", urlencode (trim ($user->first_name . " " . $user->last_name)), $url)))
368
- if (($url = preg_replace ("/%%user_email%%/i", urlencode ($user->user_email), $url)))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
369
  /**/
370
- if (($url = trim ($url))) /* Make sure it is not empty. */
371
- ws_plugin__s2member_curlpsr ($url, "s2member=1");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
372
  /**/
373
- $paypal["s2member_log"][] = "EOT/Deletion Notification URLs have been processed.";
374
  }
375
  /**/
376
- do_action ("s2member_during_paypal_notify_during_subscr_eot_demote");
 
 
 
 
 
 
 
 
 
 
377
  }
378
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_eot_behavior"] === "delete")
379
  {
380
- wp_delete_user ($user_id); /* Triggers: `ws_plugin__s2member_handle_user_deletions()` */
381
- /* `ws_plugin__s2member_handle_user_deletions()` triggers `eot_del_notification_urls` */
382
- /**/
383
- $paypal["s2member_log"][] = "The Member's account has been deleted completely.";
384
- /**/
385
- $paypal["s2member_log"][] = "EOT/Deletion Notification URLs have been processed.";
386
- /**/
387
- do_action ("s2member_during_paypal_notify_during_subscr_eot_delete");
388
  }
389
- /**/
390
- do_action ("s2member_during_paypal_notify_during_subscr_eot");
391
  }
392
  else
393
  {
394
- $paypal["s2member_log"][] = "Unable to (demote|delete) Member. Could not get the existing user_id from the DB. It's possible that it was already removed manually by a site administrator.";
395
- }
396
- /**/
397
- if (!preg_match ("/^subscr_eot$/i", $paypal["txn_type"]) && preg_match ("/^(refunded|reversed)$/i", $paypal["payment_status"]) && $paypal["parent_txn_id"])
398
- {
399
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["ref_rev_notification_urls"] && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
400
- {
401
- foreach (preg_split ("/[\r\n\t]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["ref_rev_notification_urls"]) as $url)
402
- /**/
403
- if (($url = preg_replace ("/%%cv([0-9]+)%%/ei", 'urlencode(trim($cv[$1]))', $url)) && ($url = preg_replace ("/%%subscr_id%%/i", urlencode ($paypal["subscr_id"]), $url)))
404
- if (($url = preg_replace ("/%%-amount%%/i", urlencode ($paypal["mc_gross"]), $url)) && ($url = preg_replace ("/%%parent_txn_id%%/i", urlencode ($paypal["parent_txn_id"]), $url)))
405
- if (($url = preg_replace ("/%%item_number%%/i", urlencode ($paypal["item_number"]), $url)) && ($url = preg_replace ("/%%item_name%%/i", urlencode ($paypal["item_name"]), $url)))
406
- if (($url = preg_replace ("/%%first_name%%/i", urlencode ($paypal["first_name"]), $url)) && ($url = preg_replace ("/%%last_name%%/i", urlencode ($paypal["last_name"]), $url)))
407
- if (($url = preg_replace ("/%%full_name%%/i", urlencode (trim ($paypal["first_name"] . " " . $paypal["last_name"])), $url)))
408
- if (($url = preg_replace ("/%%payer_email%%/i", urlencode ($paypal["payer_email"]), $url)))
409
- /**/
410
- if (($url = trim ($url))) /* Make sure it is not empty. */
411
- ws_plugin__s2member_curlpsr ($url, "s2member=1");
412
- /**/
413
- $paypal["s2member_log"][] = "Refund/Reversal Notification URLs have been processed.";
414
- }
415
  }
416
  }
417
  else
418
  {
419
- $paypal["s2member_log"][] = "Unable to (demote|delete) Member. Could not find existing subscription in the DB. It's possible that it was already removed manually by a site administrator.";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
  }
421
  /**/
422
  do_action ("s2member_during_paypal_notify_after_subscr_eot");
14
  if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
  exit;
16
  /*
17
+ Handles PayPal® IPN URL processing.
18
  Attach to: add_action("init");
19
  */
20
  function ws_plugin__s2member_paypal_notify ()
21
  {
22
  do_action ("s2member_before_paypal_notify");
23
  /**/
24
+ include_once ABSPATH . "wp-admin/includes/admin.php"; /* Get Admin APIs. */
25
+ /**/
26
  if ($_GET["s2member_paypal_notify"] && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"])
27
  {
28
+ if (is_array ($paypal = ws_plugin__s2member_paypal_postvars ())) /* Verify PayPal® POST vars. */
 
 
29
  {
30
+ $paypal["s2member_log"][] = "IPN received on: " . date ("D M j, Y g:i:s a T");
31
  $paypal["s2member_log"][] = "s2Member POST vars verified through a POST back to PayPal®.";
32
  /**/
33
+ $paypal["custom"] = (!$paypal["custom"]) ? ws_plugin__s2member_paypal_custom ($paypal["recurring_payment_id"]) : $paypal["custom"];
34
+ /* Notifications following the PayPal® Pro format for recurring payments, do NOT carry the "custom" value, so we do a lookup.
35
+ This is only crucial for one IPN call in Standard Integration: `txn_type=recurring_payment_suspended_due_to_max_failed_payment`.
36
+ In Pro Integrations, we just need to make sure the "custom" field is assigned for each account during on-site checkout.
37
+ This way the "custom" value will always be available when it needs to be; for both Standard and Pro services. */
38
  if (preg_match ("/^" . preg_quote ($_SERVER["HTTP_HOST"], "/") . "/i", $paypal["custom"])) /* Matches originating host? */
39
  { /* The business address validation was removed from this routine, because PayPal® always fills that with the primary
40
+ email address. In cases where an alternate PayPal® address is being paid, validation was not possible. */
41
  $paypal["s2member_log"][] = "s2Member originating domain ( _SERVER[HTTP_HOST] ) validated.";
42
  /*
43
+ Specific Post/Page Access.
44
  */
45
+ if (preg_match ("/^web_accept$/i", $paypal["txn_type"]) && $paypal["payer_email"] && $paypal["txn_id"] && preg_match ("/^sp\:[0-9,]+\:[0-9]+$/", $paypal["item_number"]))
46
  {
47
  do_action ("s2member_during_paypal_notify_before_sp_access");
48
  /**/
49
+ $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept) for Specific Post/Page Access.";
50
  /**/
51
+ list (, $paypal["sp_ids"], $paypal["hours"]) = preg_split ("/\:/", $paypal["item_number"], 3);
52
  /**/
53
+ if (($sp_access_url = ws_plugin__s2member_sp_access_link_gen ($paypal["sp_ids"], $paypal["hours"])) && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
54
  {
55
+ $processing = $during = true; /* Yes, we ARE processing this. */
56
+ /**/
57
+ $sbj = preg_replace ("/%%sp_access_url%%/i", $sp_access_url, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_email_subject"]);
58
+ $sbj = preg_replace ("/%%sp_access_exp%%/i", ws_plugin__s2member_approx_time_difference (time (), strtotime ("+" . $paypal["hours"] . " hours")), $sbj);
59
  /**/
60
+ $msg = preg_replace ("/%%sp_access_url%%/i", $sp_access_url, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_email_message"]);
61
+ $msg = preg_replace ("/%%sp_access_exp%%/i", ws_plugin__s2member_approx_time_difference (time (), strtotime ("+" . $paypal["hours"] . " hours")), $msg);
62
  /**/
63
  if (($sbj = preg_replace ("/%%cv([0-9]+)%%/ei", 'trim($cv[$1])', $sbj)) && ($sbj = preg_replace ("/%%txn_id%%/i", $paypal["txn_id"], $sbj)))
64
  if (($sbj = preg_replace ("/%%amount%%/i", $paypal["mc_gross"], $sbj))) /* Full amount of the payment, before fee is subtracted. */
78
  {
79
  @mail ($paypal["payer_email"], $sbj, $msg, "From: \"" . preg_replace ('/"/', "'", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_name"]) . "\" <" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"] . ">\r\nContent-Type: text/plain; charset=utf-8");
80
  /**/
81
+ $paypal["s2member_log"][] = "Specific Post/Page Confirmation Email sent to Customer, with a URL that provides Specific Post/Page Access.";
82
  }
83
  /**/
84
+ if ($processing && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_notification_urls"])
85
  {
86
  foreach (preg_split ("/[\r\n\t]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_notification_urls"]) as $url)
87
  /**/
88
  if (($url = preg_replace ("/%%cv([0-9]+)%%/ei", 'urlencode(trim($cv[$1]))', $url)) && ($url = preg_replace ("/%%sp_access_url%%/i", rawurlencode ($sp_access_url), $url)))
89
+ if (($url = preg_replace ("/%%sp_access_exp%%/i", urlencode (ws_plugin__s2member_approx_time_difference (time (), strtotime ("+" . $paypal["hours"] . " hours"))), $url)))
90
  if (($url = preg_replace ("/%%amount%%/i", urlencode ($paypal["mc_gross"]), $url)) && ($url = preg_replace ("/%%txn_id%%/i", urlencode ($paypal["txn_id"]), $url)))
91
  if (($url = preg_replace ("/%%item_number%%/i", urlencode ($paypal["item_number"]), $url)) && ($url = preg_replace ("/%%item_name%%/i", urlencode ($paypal["item_name"]), $url)))
92
  if (($url = preg_replace ("/%%first_name%%/i", urlencode ($paypal["first_name"]), $url)) && ($url = preg_replace ("/%%last_name%%/i", urlencode ($paypal["last_name"]), $url)))
96
  if (($url = trim ($url))) /* Make sure it is not empty. */
97
  ws_plugin__s2member_curlpsr ($url, "s2member=1");
98
  /**/
99
+ $paypal["s2member_log"][] = "Specific Post/Page Access Notification URLs have been processed.";
100
+ }
101
+ /**/
102
+ if ($processing && ($code = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_tracking_codes"]))
103
+ {
104
+ if (($code = preg_replace ("/%%cv([0-9]+)%%/ei", 'trim($cv[$1])', $code)) && ($code = preg_replace ("/%%amount%%/i", $paypal["mc_gross"], $code)) && ($code = preg_replace ("/%%txn_id%%/i", $paypal["txn_id"], $code)))
105
+ if (($code = preg_replace ("/%%item_number%%/i", $paypal["item_number"], $code)) && ($code = preg_replace ("/%%item_name%%/i", $paypal["item_name"], $code)))
106
+ if (($code = preg_replace ("/%%first_name%%/i", $paypal["first_name"], $code)) && ($code = preg_replace ("/%%last_name%%/i", $paypal["last_name"], $code)))
107
+ if (($code = preg_replace ("/%%full_name%%/i", trim ($paypal["first_name"] . " " . $paypal["last_name"]), $code)))
108
+ if (($code = preg_replace ("/%%payer_email%%/i", $paypal["payer_email"], $code)))
109
+ /**/
110
+ if (($code = trim ($code))) /* Make sure it is not empty. This gets stored into a Transient Queue. */
111
+ {
112
+ $paypal["s2member_log"][] = "Storing Specific Post/Page Tracking Codes into a Transient Queue for s2Member. These will be processed on-site.";
113
+ set_transient (md5 ("s2member_transient_sp_tracking_codes_" . $paypal["txn_id"]), $code, 43200);
114
+ }
115
  }
116
  /**/
117
  do_action ("s2member_during_paypal_notify_during_sp_access");
118
  }
119
+ else
120
+ {
121
+ $paypal["s2member_log"][] = "Unable to generate Access Link for Specific Post/Page Access. Does your Leading Post/Page still exist?";
122
+ }
123
  /**/
124
  do_action ("s2member_during_paypal_notify_after_sp_access");
125
  }
126
  /*
127
+ New Subscriptions. Possibly containing advanced update vars ( option_name1, option_selection1 ); which allow account modifications.
128
  */
129
+ else if (preg_match ("/^(web_accept|subscr_signup)$/i", $paypal["txn_type"]) && $paypal["payer_email"] && ($paypal["subscr_id"] || ($paypal["subscr_id"] = $paypal["txn_id"])) && preg_match ("/^[1-4](\:|$)([a-z_0-9,]+)?(\:)?([0-9] [A-Z])?$/", $paypal["item_number"]))
130
  {
131
  do_action ("s2member_during_paypal_notify_before_subscr_signup");
132
  /**/
133
  $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept|subscr_signup).";
134
  /**/
135
+ list ($paypal["level"], $paypal["ccaps"], $paypal["eotper"]) = preg_split ("/\:/", $paypal["item_number"], 3);
136
+ /**/
137
+ if (preg_match ("/^web_accept$/i", $paypal["txn_type"])) /* Conversions for Lifetime & Fixed-Term sales. Transform into Subscription. */
138
+ {
139
+ $paypal["period3"] = ($paypal["eotper"]) ? $paypal["eotper"] : "1 L"; /* This defaults to exactly 1 Lifetime. */
140
+ $paypal["mc_amount3"] = $paypal["mc_gross"]; /* The "Buy Now" amount. */
141
+ }
142
+ /**/
143
+ $paypal["initial_term"] = $paypal["period1"] ? $paypal["period1"] : "0 D"; /* Do not allow the initial period to be empty. Defaults to 0 D. */
144
+ $paypal["initial"] = (isset ($paypal["mc_amount1"]) && preg_match ("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
145
+ $paypal["regular"] = $paypal["mc_amount3"]; /* This is the regular payment amount that is charged to the customer. Always required by PayPal. */
146
+ $paypal["regular_term"] = $paypal["period3"]; /* This is just set to keep a standard; this way both initial_term & regular_term are available. */
147
+ $paypal["recurring"] = ($paypal["recurring"]) ? $paypal["mc_amount3"] : "0"; /* If non-recurring, this should be zero, otherwise regular. */
148
  /*
149
+ New Subscription with advanced update vars ( option_name1, option_selection1 ).
150
  */
151
+ if (preg_match ("/(updat|upgrad)/i", $paypal["option_name1"]) && $paypal["option_selection1"]) /* This is an advanced way to handle Subscription update modifications. */
152
+ /* This advanced method is required whenever a Subscription that is already completed, or was never setup to recur in the first place needs to be modified. PayPal will not allow the
153
+ modify=1|2 parameter to be used in those scenarios, because technically there is nothing to update. The only thing that actually needs to be updated is the account. */
154
  {
155
  do_action ("s2member_during_paypal_notify_before_subscr_signup_w_update_vars");
156
  /**/
157
  $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept|subscr_signup) w/ update vars.";
158
  /**/
159
+ /* Check for both the old & new subscr_id's, just in case the Return routine already changed it. */
160
+ if (($user_id = ws_plugin__s2member_paypal_user_id ($paypal["subscr_id"], $paypal["option_selection1"])))
 
161
  {
162
+ $user = new WP_User ($user_id); /* Acquire user object. */
163
+ /**/
164
+ if (!ws_plugin__s2member_user_has_wp_role ($user)) /* Non WP Roles. */
165
  {
166
+ $processing = $during = true; /* Yes, we ARE processing this. */
167
+ /**/
168
  $user->set_role ("s2member_level" . $paypal["level"]);
169
  update_usermeta ($user_id, "s2member_subscr_id", $paypal["subscr_id"]);
170
  update_usermeta ($user_id, "s2member_custom", $paypal["custom"]);
180
  delete_usermeta ($user_id, "s2member_file_download_access_arc");
181
  delete_usermeta ($user_id, "s2member_file_download_access_log");
182
  /**/
183
+ if (preg_match ("/^web_accept$/i", $paypal["txn_type"]) && $paypal["eotper"])
184
+ update_usermeta ($user_id, "s2member_auto_eot_time", ws_plugin__s2member_paypal_auto_eot_time (0, 0, 0, $paypal["eotper"]));
185
+ else /* Otherwise, we need to clear the eot time. */
186
+ delete_usermeta ($user_id, "s2member_auto_eot_time");
187
+ /**/
188
+ ws_plugin__s2member_clear_user_note_lines ($user_id, "/^Demoted by s2Member\:/");
189
+ /**/
190
  $paypal["s2member_log"][] = "s2Member Level/Capabilities updated w/ advanced update routines.";
191
  /**/
192
  @mail ($paypal["payer_email"], "Thank You! Your membership has been updated.", "Thank You! Your membership has been updated to:\n" . $paypal["item_name"] . "\n\nYou\\'ll need to log back in now.\n" . wp_login_url (), "From: \"" . preg_replace ('/"/', "'", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_name"]) . "\" <" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"] . ">\r\nContent-Type: text/plain; charset=utf-8");
197
  }
198
  else
199
  {
200
+ $paypal["s2member_log"][] = "Unable to modify Subscription. The existing User ID has a built-in WP Role. Stopping here. Otherwise, an Administrator/Editor/Author/Contributor could lose access.";
201
  }
202
  }
203
  else
204
  {
205
+ $paypal["s2member_log"][] = "Unable to modify Subscription. Could not get the existing User ID from the DB. Please check the on0 and os0 variables in your Button Code.";
206
  }
207
  /**/
208
  do_action ("s2member_during_paypal_notify_after_subscr_signup_w_update_vars");
209
  }
210
  /*
211
+ New Subscription. Normal Subscription signup, we are not updating anything for a past Subscription.
212
  */
213
+ else /* Else this is a normal Subscription signup, we are not updating anything. */
214
  {
215
  do_action ("s2member_during_paypal_notify_before_subscr_signup_wo_update_vars");
216
  /**/
218
  /**/
219
  if (($registration_url = ws_plugin__s2member_register_link_gen ($paypal["subscr_id"], $paypal["custom"], $paypal["item_number"])) && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
220
  {
221
+ $processing = $during = true; /* Yes, we ARE processing this. */
222
+ /**/
223
  $sbj = preg_replace ("/%%registration_url%%/i", $registration_url, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_email_subject"]);
224
  $msg = preg_replace ("/%%registration_url%%/i", $registration_url, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_email_message"]);
225
  /**/
 
 
 
 
 
 
 
 
 
 
 
 
226
  if (($sbj = preg_replace ("/%%cv([0-9]+)%%/ei", 'trim($cv[$1])', $sbj)) && ($sbj = preg_replace ("/%%subscr_id%%/i", $paypal["subscr_id"], $sbj)))
227
+ if (($sbj = preg_replace ("/%%initial%%/i", $paypal["initial"], $sbj)) && ($sbj = preg_replace ("/%%regular%%/i", $paypal["regular"], $sbj)) && ($sbj = preg_replace ("/%%recurring%%/i", $paypal["recurring"], $sbj)))
228
+ if (($sbj = preg_replace ("/%%initial_term%%/i", $paypal["initial_term"], $sbj)) && ($sbj = preg_replace ("/%%regular_term%%/i", $paypal["regular_term"], $sbj)))
229
  if (($sbj = preg_replace ("/%%item_number%%/i", $paypal["item_number"], $sbj)) && ($sbj = preg_replace ("/%%item_name%%/i", $paypal["item_name"], $sbj)))
230
  if (($sbj = preg_replace ("/%%first_name%%/i", $paypal["first_name"], $sbj)) && ($sbj = preg_replace ("/%%last_name%%/i", $paypal["last_name"], $sbj)))
231
  if (($sbj = preg_replace ("/%%full_name%%/i", trim ($paypal["first_name"] . " " . $paypal["last_name"]), $sbj)))
232
  if (($sbj = preg_replace ("/%%payer_email%%/i", $paypal["payer_email"], $sbj)))
233
  /**/
234
  if (($msg = preg_replace ("/%%cv([0-9]+)%%/ei", 'trim($cv[$1])', $msg)) && ($msg = preg_replace ("/%%subscr_id%%/i", $paypal["subscr_id"], $msg)))
235
+ if (($msg = preg_replace ("/%%initial%%/i", $paypal["initial"], $msg)) && ($msg = preg_replace ("/%%regular%%/i", $paypal["regular"], $msg)) && ($msg = preg_replace ("/%%recurring%%/i", $paypal["recurring"], $msg)))
236
+ if (($msg = preg_replace ("/%%initial_term%%/i", $paypal["initial_term"], $msg)) && ($msg = preg_replace ("/%%regular_term%%/i", $paypal["regular_term"], $msg)))
237
  if (($msg = preg_replace ("/%%item_number%%/i", $paypal["item_number"], $msg)) && ($msg = preg_replace ("/%%item_name%%/i", $paypal["item_name"], $msg)))
238
  if (($msg = preg_replace ("/%%first_name%%/i", $paypal["first_name"], $msg)) && ($msg = preg_replace ("/%%last_name%%/i", $paypal["last_name"], $msg)))
239
  if (($msg = preg_replace ("/%%full_name%%/i", trim ($paypal["first_name"] . " " . $paypal["last_name"]), $msg)))
252
  do_action ("s2member_during_paypal_notify_after_subscr_signup_wo_update_vars");
253
  }
254
  /**/
255
+ if ($processing && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_notification_urls"] && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
256
  {
 
 
 
 
 
 
 
 
 
 
 
 
257
  foreach (preg_split ("/[\r\n\t]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_notification_urls"]) as $url)
258
  /**/
259
  if (($url = preg_replace ("/%%cv([0-9]+)%%/ei", 'urlencode(trim($cv[$1]))', $url)) && ($url = preg_replace ("/%%subscr_id%%/i", urlencode ($paypal["subscr_id"]), $url)))
260
+ if (($url = preg_replace ("/%%initial%%/i", urlencode ($paypal["initial"]), $url)) && ($url = preg_replace ("/%%regular%%/i", urlencode ($paypal["regular"]), $url)) && ($url = preg_replace ("/%%recurring%%/i", urlencode ($paypal["recurring"]), $url)))
261
+ if (($url = preg_replace ("/%%initial_term%%/i", urlencode ($paypal["initial_term"]), $url)) && ($url = preg_replace ("/%%regular_term%%/i", urlencode ($paypal["regular_term"]), $url)))
262
  if (($url = preg_replace ("/%%item_number%%/i", urlencode ($paypal["item_number"]), $url)) && ($url = preg_replace ("/%%item_name%%/i", urlencode ($paypal["item_name"]), $url)))
263
  if (($url = preg_replace ("/%%first_name%%/i", urlencode ($paypal["first_name"]), $url)) && ($url = preg_replace ("/%%last_name%%/i", urlencode ($paypal["last_name"]), $url)))
264
  if (($url = preg_replace ("/%%full_name%%/i", urlencode (trim ($paypal["first_name"] . " " . $paypal["last_name"])), $url)))
270
  $paypal["s2member_log"][] = "Signup Notification URLs have been processed.";
271
  }
272
  /**/
273
+ if ($processing && ($code = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_tracking_codes"]) && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
274
+ {
275
+ if (($code = preg_replace ("/%%cv([0-9]+)%%/ei", 'trim($cv[$1])', $code)) && ($code = preg_replace ("/%%subscr_id%%/i", $paypal["subscr_id"], $code)))
276
+ if (($code = preg_replace ("/%%initial%%/i", $paypal["initial"], $code)) && ($code = preg_replace ("/%%regular%%/i", $paypal["regular"], $code)) && ($code = preg_replace ("/%%recurring%%/i", $paypal["recurring"], $code)))
277
+ if (($code = preg_replace ("/%%initial_term%%/i", $paypal["initial_term"], $code)) && ($code = preg_replace ("/%%regular_term%%/i", $paypal["regular_term"], $code)))
278
+ if (($code = preg_replace ("/%%item_number%%/i", $paypal["item_number"], $code)) && ($code = preg_replace ("/%%item_name%%/i", $paypal["item_name"], $code)))
279
+ if (($code = preg_replace ("/%%first_name%%/i", $paypal["first_name"], $code)) && ($code = preg_replace ("/%%last_name%%/i", $paypal["last_name"], $code)))
280
+ if (($code = preg_replace ("/%%full_name%%/i", trim ($paypal["first_name"] . " " . $paypal["last_name"]), $code)))
281
+ if (($code = preg_replace ("/%%payer_email%%/i", $paypal["payer_email"], $code)))
282
+ /**/
283
+ if (($code = trim ($code))) /* Make sure it is not empty. This gets stored into a Transient Queue. */
284
+ {
285
+ $paypal["s2member_log"][] = "Storing Signup Tracking Codes into a Transient Queue for s2Member. These will be processed on-site.";
286
+ set_transient (md5 ("s2member_transient_signup_tracking_codes_" . $paypal["subscr_id"]), $code, 43200);
287
+ }
288
+ }
289
+ /**/
290
+ if ($processing && preg_match ("/^web_accept$/i", $paypal["txn_type"]) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["payment_notification_urls"] && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
291
+ {
292
+ foreach (preg_split ("/[\r\n\t]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["payment_notification_urls"]) as $url)
293
+ /**/
294
+ if (($url = preg_replace ("/%%cv([0-9]+)%%/ei", 'urlencode(trim($cv[$1]))', $url)) && ($url = preg_replace ("/%%subscr_id%%/i", urlencode ($paypal["subscr_id"]), $url)))
295
+ if (($url = preg_replace ("/%%amount%%/i", urlencode ($paypal["mc_gross"]), $url)) && ($url = preg_replace ("/%%txn_id%%/i", urlencode ($paypal["txn_id"]), $url)))
296
+ if (($url = preg_replace ("/%%item_number%%/i", urlencode ($paypal["item_number"]), $url)) && ($url = preg_replace ("/%%item_name%%/i", urlencode ($paypal["item_name"]), $url)))
297
+ if (($url = preg_replace ("/%%first_name%%/i", urlencode ($paypal["first_name"]), $url)) && ($url = preg_replace ("/%%last_name%%/i", urlencode ($paypal["last_name"]), $url)))
298
+ if (($url = preg_replace ("/%%full_name%%/i", urlencode (trim ($paypal["first_name"] . " " . $paypal["last_name"])), $url)))
299
+ if (($url = preg_replace ("/%%payer_email%%/i", urlencode ($paypal["payer_email"]), $url)))
300
+ /**/
301
+ if (($url = trim ($url))) /* Make sure it is not empty. */
302
+ ws_plugin__s2member_curlpsr ($url, "s2member=1");
303
+ /**/
304
+ $paypal["s2member_log"][] = "Payment Notification URLs have been processed.";
305
+ }
306
+ /**/
307
  do_action ("s2member_during_paypal_notify_after_subscr_signup");
308
  }
309
  /*
310
  Subscription modifications.
311
  */
312
+ else if (preg_match ("/^subscr_modify$/i", $paypal["txn_type"]) && $paypal["payer_email"] && $paypal["subscr_id"] && preg_match ("/^[1-4](\:|$)([a-z_0-9,]+)?(\:)?([0-9] [A-Z])?$/", $paypal["item_number"]))
313
  {
314
  do_action ("s2member_during_paypal_notify_before_subscr_modify");
315
  /**/
317
  /**/
318
  list ($paypal["level"], $paypal["ccaps"]) = preg_split ("/\:/", $paypal["item_number"], 2);
319
  /**/
320
+ if (($user_id = ws_plugin__s2member_paypal_user_id ($paypal["subscr_id"])))
321
  {
322
+ $user = new WP_User ($user_id); /* Acquire user object. */
323
+ /**/
324
+ if (!ws_plugin__s2member_user_has_wp_role ($user)) /* Non WP Roles. */
325
  {
326
+ $processing = $during = true; /* Yes, we ARE processing this. */
327
+ /**/
328
  $user->set_role ("s2member_level" . $paypal["level"]);
329
  update_usermeta ($user_id, "s2member_subscr_id", $paypal["subscr_id"]);
330
  update_usermeta ($user_id, "s2member_custom", $paypal["custom"]);
339
  /**/
340
  delete_usermeta ($user_id, "s2member_file_download_access_arc");
341
  delete_usermeta ($user_id, "s2member_file_download_access_log");
342
+ delete_usermeta ($user_id, "s2member_auto_eot_time");
343
  /**/
344
+ ws_plugin__s2member_clear_user_note_lines ($user_id, "/^Demoted by s2Member\:/");
345
+ /**/
346
+ $paypal["s2member_log"][] = "s2Member Level/Capabilities updated on Subscription modification.";
347
  /**/
348
  @mail ($paypal["payer_email"], "Thank You! Your membership has been updated.", "Thank You! Your membership has been updated to:\n" . $paypal["item_name"] . "\n\nYou\\'ll need to log back in now.\n" . wp_login_url (), "From: \"" . preg_replace ('/"/', "'", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_name"]) . "\" <" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"] . ">\r\nContent-Type: text/plain; charset=utf-8");
349
  /**/
353
  }
354
  else
355
  {
356
+ $paypal["s2member_log"][] = "Unable to modify Subscription. The existing User ID has a built-in WP Role. Stopping here. Otherwise, an Administrator/Editor/Author/Contributor could lose access.";
357
  }
358
  }
359
  else
360
  {
361
+ $paypal["s2member_log"][] = "Unable to modify Subscription. Could not get the existing User ID from the DB.";
362
  }
363
  /**/
364
  do_action ("s2member_during_paypal_notify_after_subscr_modify");
366
  /*
367
  Subscription payments.
368
  */
369
+ else if (preg_match ("/^subscr_payment$/i", $paypal["txn_type"]) && $paypal["payer_email"] && $paypal["subscr_id"] && preg_match ("/^[1-4](\:|$)([a-z_0-9,]+)?(\:)?([0-9] [A-Z])?$/", $paypal["item_number"]) && $paypal["txn_id"] && $paypal["mc_gross"])
370
  {
371
  do_action ("s2member_during_paypal_notify_before_subscr_payment");
372
  /**/
373
  $paypal["s2member_log"][] = "s2Member txn_type identified as subscr_payment.";
374
+ $paypal["s2member_log"][] = "Sleeping for 2 seconds. Waiting for a possible subscr_signup|subscr_modify.";
375
+ sleep (2); /* Sleep here for a moment. PayPal® sometimes sends a subscr_payment before the subscr_signup, subscr_modify.
376
+ It is NOT a big deal if they do. However, s2Member goes to sleep here, just to help keep the log files in a logical order. */
377
+ $paypal["s2member_log"][] = "Awake. It's " . date ("D M j, Y g:i:s a T") . ". s2Member txn_type identified as subscr_payment.";
378
  /**/
379
  list ($paypal["level"], $paypal["ccaps"]) = preg_split ("/\:/", $paypal["item_number"], 2);
380
  /**/
381
+ if (($user_id = ws_plugin__s2member_paypal_user_id ($paypal["subscr_id"], $paypal["option_selection1"])))
382
  {
383
+ $processing = $during = true; /* Yes, we ARE processing this. */
 
 
 
 
 
 
 
 
 
 
384
  /**/
385
+ update_usermeta ($user_id, "s2member_last_payment_time", time ());
386
+ /**/
387
+ $paypal["s2member_log"][] = "Updated Last Payment Time for this Member.";
388
+ /**/
389
+ if ($processing && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["payment_notification_urls"] && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
390
+ {
391
+ foreach (preg_split ("/[\r\n\t]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["payment_notification_urls"]) as $url)
392
+ /**/
393
+ if (($url = preg_replace ("/%%cv([0-9]+)%%/ei", 'urlencode(trim($cv[$1]))', $url)) && ($url = preg_replace ("/%%subscr_id%%/i", urlencode ($paypal["subscr_id"]), $url)))
394
+ if (($url = preg_replace ("/%%amount%%/i", urlencode ($paypal["mc_gross"]), $url)) && ($url = preg_replace ("/%%txn_id%%/i", urlencode ($paypal["txn_id"]), $url)))
395
+ if (($url = preg_replace ("/%%item_number%%/i", urlencode ($paypal["item_number"]), $url)) && ($url = preg_replace ("/%%item_name%%/i", urlencode ($paypal["item_name"]), $url)))
396
+ if (($url = preg_replace ("/%%first_name%%/i", urlencode ($paypal["first_name"]), $url)) && ($url = preg_replace ("/%%last_name%%/i", urlencode ($paypal["last_name"]), $url)))
397
+ if (($url = preg_replace ("/%%full_name%%/i", urlencode (trim ($paypal["first_name"] . " " . $paypal["last_name"])), $url)))
398
+ if (($url = preg_replace ("/%%payer_email%%/i", urlencode ($paypal["payer_email"]), $url)))
399
+ /**/
400
+ if (($url = trim ($url))) /* Make sure it is not empty. */
401
+ ws_plugin__s2member_curlpsr ($url, "s2member=1");
402
+ /**/
403
+ $paypal["s2member_log"][] = "Payment Notification URLs have been processed.";
404
+ }
405
+ /**/
406
+ do_action ("s2member_during_paypal_notify_during_subscr_payment");
407
+ }
408
+ else
409
+ {
410
+ $paypal["s2member_log"][] = "Skipping this IPN response, for now. The Subscr. ID is not associated with a registered Member.";
411
+ $paypal["s2member_log"][] = "Storing this IPN response into a Transient Queue for s2Member. This will be re-processed when registration occurs.";
412
+ set_transient (md5 ("s2member_transient_ipn_subscr_payment_" . $paypal["subscr_id"]), $_POST, 43200);
413
  }
414
  /**/
415
  do_action ("s2member_during_paypal_notify_after_subscr_payment");
416
  }
417
  /*
418
+ Subscription cancellations. s2Member can use this, to determine when/if it should Auto-EOT (demote|delete) a Member's account.
419
+ The IPN for `subscr_cancel` is compatible with newer PayPal® accounts that do NOT send a subscr_eot when an account is cancelled.
420
+ This works in conjunction with `s2member_last_payment_time`, and the s2Member Auto-EOT System.
421
+ For further details & stupidity, see: https://www.x.com/thread/41155?start=15&tstart=0
422
  */
423
+ else if (preg_match ("/^subscr_cancel$/i", $paypal["txn_type"]) && $paypal["payer_email"] && $paypal["subscr_id"] && preg_match ("/^[1-4](\:|$)([a-z_0-9,]+)?(\:)?([0-9] [A-Z])?$/", $paypal["item_number"]))
424
  {
425
+ do_action ("s2member_during_paypal_notify_before_subscr_cancel");
426
  /**/
427
+ $paypal["s2member_log"][] = "s2Member txn_type identified as subscr_cancel.";
428
  /**/
429
  list ($paypal["level"], $paypal["ccaps"]) = preg_split ("/\:/", $paypal["item_number"], 2);
430
  /**/
431
+ if (($user_id = ws_plugin__s2member_paypal_user_id ($paypal["subscr_id"])))
432
  {
433
+ if (!get_usermeta ($user_id, "s2member_auto_eot_time")) /* Respect existing. */
434
+ {
435
+ $processing = $during = true; /* Yes, we ARE processing this. */
436
+ /**/
437
+ $auto_eot_time = ws_plugin__s2member_paypal_auto_eot_time ($user_id, $paypal["period1"], $paypal["period3"]);
438
+ /**/
439
+ update_usermeta ($user_id, "s2member_auto_eot_time", $auto_eot_time); /* s2Member will follow-up on this later. */
440
+ /**/
441
+ $paypal["s2member_log"][] = "Auto-EOT Time for this account: " . date ("D M j, Y g:i a T", $auto_eot_time);
442
+ /**/
443
+ do_action ("s2member_during_paypal_notify_during_subscr_cancel");
444
+ }
445
+ else
446
  {
447
+ $paypal["s2member_log"][] = "Ignoring Cancellation. An Auto-EOT Time is already set for this Member.";
448
+ }
449
+ }
450
+ else
451
+ {
452
+ $paypal["s2member_log"][] = "Unable to handle Cancellation. Could not get the existing User ID from the DB.";
453
+ }
454
+ /**/
455
+ do_action ("s2member_during_paypal_notify_after_subscr_cancel");
456
+ }
457
+ /*
458
+ Subscription terminations, max failed payments, initial payment failed, chargebacks, refunds, and reversals. *** NOT processed for Specific Posts/Pages. */
459
+ else if ( /* An immediate EOT is necessary under MANY different conditions. This consolidates them all, with a sub-classification for refunds/reversals. */
460
+ (preg_match ("/^(subscr_eot|recurring_payment_expired|recurring_payment_suspended_due_to_max_failed_payment)$/i", $paypal["txn_type"]) || (preg_match ("/^recurring_payment_profile_cancel$/i", $paypal["txn_type"]) && preg_match ("/^failed$/i", $paypal["initial_payment_status"])) || (preg_match ("/^new_case$/i", $paypal["txn_type"]) && preg_match ("/^chargeback$/i", $paypal["case_type"])) || (!$paypal["txn_type"] && preg_match ("/^(refunded|reversed)$/i", $paypal["payment_status"])))/**/
461
+ && ($paypal["subscr_id"] || ($paypal["subscr_id"] = $paypal["recurring_payment_id"]) || ($paypal["subscr_id"] = $paypal["parent_txn_id"]))/**/
462
+ && (preg_match ("/^[1-4](\:|$)([a-z_0-9,]+)?(\:)?([0-9] [A-Z])?$/", $paypal["item_number"]) || $paypal["recurring_payment_id"])/**/)
463
+ {
464
+ do_action ("s2member_during_paypal_notify_before_subscr_eot");
465
+ /**/
466
+ $paypal["s2member_log"][] = "s2Member txn_type identified as (subscr_eot|recurring_payment_expired|recurring_payment_suspended_due_to_max_failed_payment) - or - initial_payment_status (failed) - or - case_type (chargeback) - or - payment_status (refunded|reversed).";
467
+ /**/
468
+ if (($user_id = ws_plugin__s2member_paypal_user_id ($paypal["subscr_id"], $paypal["option_selection1"])))
469
+ {
470
+ if (!get_usermeta ($user_id, "s2member_auto_eot_time")) /* Respect Auto-EOT. */
471
+ {
472
+ $user = new WP_User ($user_id); /* Acquire user object. */
473
+ /**/
474
+ if (!ws_plugin__s2member_user_has_wp_role ($user)) /* Non WP Roles. */
475
  {
476
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["auto_eot_system_enabled"]) /* EOT enabled? */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
477
  {
478
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_eot_behavior"] === "demote")
479
+ {
480
+ $processing = $during = true; /* Yes, we ARE processing this. */
481
+ /**/
482
+ $user->set_role ("subscriber");
483
+ /**/
484
+ delete_usermeta ($user_id, "s2member_custom");
485
+ delete_usermeta ($user_id, "s2member_subscr_id");
486
+ delete_usermeta ($user_id, "s2member_last_payment_time");
487
+ delete_usermeta ($user_id, "s2member_auto_eot_time");
488
+ /**/
489
+ foreach ($user->allcaps as $cap => $cap_enabled)
490
+ if (preg_match ("/^access_s2member_ccap_/", $cap))
491
+ $user->remove_cap ($ccap = $cap);
492
+ /**/
493
+ delete_usermeta ($user_id, "s2member_file_download_access_arc");
494
+ delete_usermeta ($user_id, "s2member_file_download_access_log");
495
+ /**/
496
+ ws_plugin__s2member_append_user_notes ($user_id, "Demoted by s2Member: " . date ("D M j, Y g:i a T"));
497
+ /**/
498
+ $paypal["s2member_log"][] = "Member Level/Capabilities demoted to a Free Subscriber.";
499
+ /**/
500
+ if ($processing && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_del_notification_urls"] && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
501
+ {
502
+ foreach (preg_split ("/[\r\n\t]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_del_notification_urls"]) as $url) /* Handle eot notifications. */
503
  /**/
504
+ if (($url = preg_replace ("/%%cv([0-9]+)%%/ei", 'urlencode(trim($cv[$1]))', $url)) && ($url = preg_replace ("/%%subscr_id%%/i", urlencode ($paypal["subscr_id"]), $url)))
505
+ if (($url = preg_replace ("/%%user_first_name%%/i", urlencode ($user->first_name), $url)) && ($url = preg_replace ("/%%user_last_name%%/i", urlencode ($user->last_name), $url)))
506
+ if (($url = preg_replace ("/%%user_full_name%%/i", urlencode (trim ($user->first_name . " " . $user->last_name)), $url)))
507
+ if (($url = preg_replace ("/%%user_email%%/i", urlencode ($user->user_email), $url)))
508
+ /**/
509
+ if (($url = trim ($url))) /* Make sure it is not empty. */
510
+ ws_plugin__s2member_curlpsr ($url, "s2member=1");
511
+ /**/
512
+ $paypal["s2member_log"][] = "EOT/Deletion Notification URLs have been processed.";
513
+ }
514
+ /**/
515
+ do_action ("s2member_during_paypal_notify_during_subscr_eot_demote");
516
+ }
517
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_eot_behavior"] === "delete")
518
+ {
519
+ $processing = $during = true; /* Yes, we ARE processing this. */
520
+ /**/
521
+ wp_delete_user ($user_id); /* Triggers: `ws_plugin__s2member_handle_user_deletions()` */
522
+ /* `ws_plugin__s2member_handle_user_deletions()` triggers `eot_del_notification_urls` */
523
+ /**/
524
+ $paypal["s2member_log"][] = "The Member's account has been deleted completely.";
525
+ /**/
526
+ $paypal["s2member_log"][] = "EOT/Deletion Notification URLs have been processed.";
527
+ /**/
528
+ do_action ("s2member_during_paypal_notify_during_subscr_eot_delete");
529
+ }
530
  /**/
531
+ do_action ("s2member_during_paypal_notify_during_subscr_eot");
532
  }
533
  /**/
534
+ else /* Otherwise, treat this as if it were a cancellation. EOTs are currently disabled. */
535
+ {
536
+ $processing = $during = true; /* Yes, we ARE processing this. */
537
+ /**/
538
+ update_usermeta ($user_id, "s2member_auto_eot_time", ($auto_eot_time = strtotime ("now")));
539
+ /**/
540
+ $paypal["s2member_log"][] = "Auto-EOT is currently disabled. Skipping immediate EOT (demote|delete), for now.";
541
+ $paypal["s2member_log"][] = "Recording the Auto-EOT Time for this Member's account: " . date ("D M j, Y g:i a T", $auto_eot_time);
542
+ /**/
543
+ do_action ("s2member_during_paypal_notify_during_subscr_eot_disabled");
544
+ }
545
  }
546
+ else
547
  {
548
+ $paypal["s2member_log"][] = "Unable to (demote|delete) Member. The existing User ID has a built-in WP Role. Stopping here. Otherwise, an Administrator/Editor/Author/Contributor could lose access.";
 
 
 
 
 
 
 
549
  }
 
 
550
  }
551
  else
552
  {
553
+ $paypal["s2member_log"][] = "Skipping (demote|delete) Member, for now. An Auto-EOT Time is already set. When an Auto-EOT Time has been recorded, s2Member will handle EOT (demote|delete) events using it's own Auto-EOT System.";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
554
  }
555
  }
556
  else
557
  {
558
+ $paypal["s2member_log"][] = "Unable to (demote|delete) Member. Could not get the existing User ID from the DB. It's possible that it was already removed manually by a Site Administrator, or by s2Member's Auto-EOT System.";
559
+ }
560
+ /*
561
+ Refunds and chargeback reversals. This is excluded from the processing check, because a Member *could* have already been (demoted|deleted).
562
+ In other words, s2Member sends `Refund/Reversal` Notifications ANYTIME a Refund/Reversal occurs; even if s2Member did not process it otherwise.
563
+ Since this routine ignores the processing check, it is *possible* that Refund/Reversal Notification URLs will be contacted more than once.
564
+ If you are writing scripts that depend on Refund/Reversal Notifications, please keep this in mind.
565
+ */
566
+ if (!$paypal["txn_type"] && preg_match ("/^(refunded|reversed)$/i", $paypal["payment_status"]) && $paypal["parent_txn_id"])
567
+ {
568
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["ref_rev_notification_urls"] && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
569
+ {
570
+ foreach (preg_split ("/[\r\n\t]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["ref_rev_notification_urls"]) as $url)
571
+ /**/
572
+ if (($url = preg_replace ("/%%cv([0-9]+)%%/ei", 'urlencode(trim($cv[$1]))', $url)) && ($url = preg_replace ("/%%subscr_id%%/i", urlencode ($paypal["subscr_id"]), $url)))
573
+ if (($url = preg_replace ("/%%-amount%%/i", urlencode ($paypal["mc_gross"]), $url)) && ($url = preg_replace ("/%%parent_txn_id%%/i", urlencode ($paypal["parent_txn_id"]), $url)))
574
+ if (($url = preg_replace ("/%%item_number%%/i", urlencode ($paypal["item_number"]), $url)) && ($url = preg_replace ("/%%item_name%%/i", urlencode ($paypal["item_name"]), $url)))
575
+ if (($url = preg_replace ("/%%first_name%%/i", urlencode ($paypal["first_name"]), $url)) && ($url = preg_replace ("/%%last_name%%/i", urlencode ($paypal["last_name"]), $url)))
576
+ if (($url = preg_replace ("/%%full_name%%/i", urlencode (trim ($paypal["first_name"] . " " . $paypal["last_name"])), $url)))
577
+ if (($url = preg_replace ("/%%payer_email%%/i", urlencode ($paypal["payer_email"]), $url)))
578
+ /**/
579
+ if (($url = trim ($url))) /* Make sure it is not empty. */
580
+ ws_plugin__s2member_curlpsr ($url, "s2member=1");
581
+ /**/
582
+ $paypal["s2member_log"][] = "Refund/Reversal Notification URLs have been processed.";
583
+ }
584
+ /**/
585
+ do_action ("s2member_during_paypal_notify_during_subscr_eot_refund_reversal");
586
  }
587
  /**/
588
  do_action ("s2member_during_paypal_notify_after_subscr_eot");
includes/functions/paypal-postvars.inc.php DELETED
@@ -1,73 +0,0 @@
1
- <?php
2
- /*
3
- Copyright: © 2009 WebSharks, Inc. ( coded in the USA )
4
- <mailto:support@websharks-inc.com> <http://www.websharks-inc.com/>
5
-
6
- Released under the terms of the GNU General Public License.
7
- You should have received a copy of the GNU General Public License,
8
- along with this software. In the main directory, see: /licensing/
9
- If not, see: <http://www.gnu.org/licenses/>.
10
- */
11
- /*
12
- Direct access denial.
13
- */
14
- if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
- exit;
16
- /*
17
- Get post vars from paypal, verify and return array.
18
- */
19
- function ws_plugin__s2member_paypal_postvars ()
20
- {
21
- do_action ("s2member_before_paypal_postvars");
22
- /**/
23
- if ($_GET["tx"]) /* PDT with Auto-Return. */
24
- {
25
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_identity_token"])
26
- {
27
- $postback = "cmd=_notify-synch";
28
- /**/
29
- $postback .= "&tx=" . urlencode ($_GET["tx"]);
30
- $postback .= "&at=" . urlencode ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_identity_token"]);
31
- /**/
32
- $endpoint = ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com";
33
- /**/
34
- if (preg_match ("/^SUCCESS/i", ($response = trim (ws_plugin__s2member_curlpsr ("https://" . $endpoint . "/cgi-bin/webscr", $postback)))))
35
- {
36
- foreach (preg_split ("/[\r\n]+/", preg_replace ("/^SUCCESS/i", "", $response)) as $varline)
37
- {
38
- list ($key, $value) = preg_split ("/\=/", $varline, 2);
39
- if (strlen ($key = trim ($key)) && strlen ($value = trim ($value)))
40
- $postvars[$key] = trim (stripslashes (urldecode ($value)));
41
- }
42
- /**/
43
- return apply_filters ("s2member_paypal_postvars", $postvars);
44
- }
45
- }
46
- /**/
47
- return false;
48
- }
49
- else if (is_array ($postvars = stripslashes_deep ($_POST)))
50
- {
51
- $postback = "cmd=_notify-validate";
52
- /**/
53
- foreach ($postvars as $key => $value)
54
- $postback .= "&" . $key . "=" . urlencode ($value);
55
- /**/
56
- foreach ($postvars as $key => $value)
57
- $postvars[$key] = trim ($value);
58
- /**/
59
- $endpoint = ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com";
60
- /**/
61
- if (strtolower (trim (ws_plugin__s2member_curlpsr ("https://" . $endpoint . "/cgi-bin/webscr", $postback))) === "verified")
62
- {
63
- return apply_filters ("s2member_paypal_postvars", $postvars);
64
- }
65
- /**/
66
- return false;
67
- }
68
- else /* Unable to obtain. */
69
- {
70
- return false;
71
- }
72
- }
73
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/functions/paypal-return.inc.php CHANGED
@@ -14,7 +14,7 @@ Direct access denial.
14
  if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
  exit;
16
  /*
17
- Handles paypal return url processing.
18
  Attach to: add_action("init");
19
  */
20
  function ws_plugin__s2member_paypal_return ()
@@ -23,53 +23,73 @@ function ws_plugin__s2member_paypal_return ()
23
  /**/
24
  if ($_GET["s2member_paypal_return"] && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"])
25
  {
26
- global $wpdb; /* Need this global variable as a reference to the database object. */
27
- /**/
28
- if (is_object ($wpdb) && is_array ($paypal = ws_plugin__s2member_paypal_postvars ()))
29
  {
 
30
  $paypal["s2member_log"][] = "s2Member POST vars verified through a POST back to PayPal®.";
31
  /**/
32
  if (preg_match ("/^" . preg_quote ($_SERVER["HTTP_HOST"], "/") . "/i", $paypal["custom"])) /* Matches originating host? */
33
  { /* The business address validation was removed from this routine, because PayPal® always fills that with the primary
34
- email address. In cases where an alternate PayPal® address is being paid, validation is not possible. */
35
  $paypal["s2member_log"][] = "s2Member originating domain ( _SERVER[HTTP_HOST] ) validated.";
36
  /*
37
- Single-Page Access.
38
  */
39
- if (preg_match ("/^web_accept$/i", $paypal["txn_type"]) && $paypal["txn_id"] && preg_match ("/^sp\:[0-9]+\:[0-9]+$/", $paypal["item_number"]))
40
  {
41
  do_action ("s2member_during_paypal_return_before_sp_access");
42
  /**/
43
- $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept) for Single-Page access.";
44
  /**/
45
- list (, $paypal["page"], $paypal["hours"]) = preg_split ("/\:/", $paypal["item_number"], 3);
46
  /**/
47
- if (($sp_access_url = ws_plugin__s2member_sp_access_link_gen ($paypal["page"], $paypal["hours"], false)))
48
  {
49
- $paypal["s2member_log"][] = "Redirecting Customer to the Single-Page.";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  /**/
51
  do_action ("s2member_during_paypal_return_during_sp_access");
52
  /**/
 
 
53
  header ("Location: " . $sp_access_url);
54
  }
55
- else /* Otherwise, the page ID must have been invalid. Or it's possible that the Page was deleted. */
56
  {
57
- $paypal["s2member_log"][] = "Unable to generate Single-Page Access Link.";
 
 
58
  /**/
59
  echo '<script type="text/javascript">' . "\n";
60
  echo "alert('ERROR: Unable to generate Access Link. Please contact Support for assistance.');" . "\n";
61
  echo "window.location = '" . esc_js (get_bloginfo ("url")) . "';";
62
  echo '</script>' . "\n";
63
- /**/
64
- $paypal["s2member_log"][] = "Redirecting Customer to the Home Page, due to an error that occurred.";
65
  }
66
  /**/
67
  do_action ("s2member_during_paypal_return_after_sp_access");
68
  }
69
  /*
70
- New subscriptions. Possibly containing advanced updated vars ( option_name1, option_selection1 ); which allow account modifications.
71
  */
72
- else if (preg_match ("/^(web_accept|subscr_signup|subscr_payment)$/i", $paypal["txn_type"]) && ($paypal["subscr_id"] || ($paypal["subscr_id"] = $paypal["txn_id"])) && preg_match ("/^[1-4](\:|$)/", $paypal["item_number"]))
73
  { /* With Auto-Return/PDT, PayPal will send subscr_payment instead of subscr_signup to the return URL.
74
  So we need to look for (web_accept|subscr_signup|subscr_payment), and treat them as the same. */
75
  /**/
@@ -77,25 +97,27 @@ function ws_plugin__s2member_paypal_return ()
77
  /**/
78
  $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept|subscr_signup|subscr_payment).";
79
  /**/
80
- list ($paypal["level"], $paypal["ccaps"]) = preg_split ("/\:/", $paypal["item_number"], 2);
81
  /*
82
- New subscription with advanced update vars ( option_name1, option_selection1 ).
83
  */
84
- if (preg_match ("/(updat|upgrad)/i", $paypal["option_name1"]) && $paypal["option_selection1"]) /* Advanced subscription update modifications. */
85
- /* This advanced method is required whenever a subscription that is already completed, or was never setup to recur in the first place needs to be modified. PayPal® will not allow the
86
- modify=2 parameter to be used in those scenarios, because technically there is nothing to update. The only thing to be updated is the existing account. */
87
  {
88
  do_action ("s2member_during_paypal_return_before_subscr_signup_w_update_vars");
89
  /**/
90
  $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept|subscr_signup|subscr_payment) w/ update vars.";
91
  /**/
92
- /* Here we need to check for both the old & new s2member_subscr_id's, just in case the IPN routine has already changed it. */
93
- if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = 's2member_subscr_id' AND (`meta_value` = '" . $wpdb->escape ($paypal["option_selection1"]) . "' OR `meta_value` = '" . $wpdb->escape ($paypal["subscr_id"]) . "') LIMIT 1"))/**/
94
- || ($q = $wpdb->get_row ("SELECT `ID` AS `user_id` FROM `" . $wpdb->users . "` WHERE `ID` = '" . $wpdb->escape ($paypal["option_selection1"]) . "' LIMIT 1")))
95
  {
96
- if ($user_id = $q->user_id) /* Got it! */
 
 
97
  {
98
- $user = new WP_User ($user_id);
 
99
  $user->set_role ("s2member_level" . $paypal["level"]);
100
  update_usermeta ($user_id, "s2member_subscr_id", $paypal["subscr_id"]);
101
  update_usermeta ($user_id, "s2member_custom", $paypal["custom"]);
@@ -111,154 +133,75 @@ function ws_plugin__s2member_paypal_return ()
111
  delete_usermeta ($user_id, "s2member_file_download_access_arc");
112
  delete_usermeta ($user_id, "s2member_file_download_access_log");
113
  /**/
 
 
 
 
 
 
 
114
  $paypal["s2member_log"][] = "s2Member Level/Capabilities updated w/ advanced update routines.";
115
  /**/
116
  do_action ("s2member_during_paypal_return_during_subscr_signup_w_update_vars");
117
  /**/
118
- echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "\n";
119
- echo '<html xmlns="http://www.w3.org/1999/xhtml" ', language_attributes (), '>' . "\n";
120
- echo '<head profile="http://gmpg.org/xfn/11">' . "\n";
121
- echo '<meta http-equiv="Content-Type" content="' . get_bloginfo ("html_type") . '; charset=' . get_bloginfo ("charset") . '" />' . "\n";
122
- echo '<script type="text/javascript">' . "\n"; /* Onload allows any tracking codes to finish loading. */
123
- echo "window.onload = function(){ " . "\n"; /* After everything has finished loading, we alert and then redirect. */
124
  echo "alert('Thank You! Your membership has been updated to:\\n\\n" . esc_js ($paypal["item_name"]) . "\\n\\nYou\\'ll need to log back in now.');" . "\n";
125
- echo "window.location = '" . wp_login_url () . "'; };" . "\n";
126
  echo '</script>' . "\n";
127
- echo '</head>' . "\n";
128
- /**/
129
- echo '<body style="background:#' . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_background_color"] . ' url(' . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_background_image"] . ');">' . "\n";
130
- /**/
131
- echo '<!-- Tracking codes from the s2Member plugin for WordPress. -->' . "\n";
132
- /**/
133
- if (($code = trim ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_tracking_codes"])) && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
134
- {
135
- if (preg_match ("/^subscr_signup$/i", $paypal["txn_type"]))
136
- $initial = (isset ($paypal["mc_amount1"]) && preg_match ("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
137
- /* The initial amount will only be $0 if a trial was offered. If no trial was offered, they were charged a regular rate. */
138
- else if (preg_match ("/^(web_accept|subscr_payment)$/i", $paypal["txn_type"])) /* PDT w/Auto-Return sends subscr_payment. */
139
- $initial = $paypal["mc_gross"]; /* Here, the initial payment is provided clearly as the payment gross. */
140
- /**/
141
- if (($code = preg_replace ("/%%cv([0-9]+)%%/ei", 'trim($cv[$1])', $code)) && ($code = preg_replace ("/%%subscr_id%%/i", $paypal["subscr_id"], $code)))
142
- if (($code = preg_replace ("/%%initial%%/i", $initial, $code))) /* Adv calculations here. We have to support both sets of variables, subscr_signup & subscr_payment. */
143
- if (($code = preg_replace ("/%%item_number%%/i", $paypal["item_number"], $code)) && ($code = preg_replace ("/%%item_name%%/i", $paypal["item_name"], $code)))
144
- if (($code = preg_replace ("/%%first_name%%/i", $paypal["first_name"], $code)) && ($code = preg_replace ("/%%last_name%%/i", $paypal["last_name"], $code)))
145
- if (($code = preg_replace ("/%%full_name%%/i", trim ($paypal["first_name"] . " " . $paypal["last_name"]), $code)))
146
- if (($code = preg_replace ("/%%payer_email%%/i", $paypal["payer_email"], $code)))
147
- /**/
148
- if (($code = trim ($code))) /* Make sure it is not empty. */
149
- /**/
150
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["is_wpmu"])
151
- {
152
- echo $code . "\n"; /* No PHP allowed here. */
153
- $paypal["s2member_log"][] = "Signup Tracking codes have been processed.";
154
- }
155
- else /* Otherwise, it's safe to allow PHP code. */
156
- {
157
- eval ("?>" . $code);
158
- $paypal["s2member_log"][] = "Signup Tracking codes have been evaluated.";
159
- }
160
- }
161
- /**/
162
- echo '<!-- Tracking codes from the s2Member plugin for WordPress. -->' . "\n";
163
- /**/
164
- $paypal["s2member_log"][] = "Success! Redirecting Customer to the Login Page. They need to log back in after this modification.";
165
- /**/
166
- echo '</body>' . "\n";
167
- echo '</html>';
168
  }
169
  else
170
  {
171
- $paypal["s2member_log"][] = "Unable to modify subscription. Could not get the existing user_id from the DB. Please check the on0 and os0 variables in your Button Code.";
 
 
172
  /**/
173
  echo '<script type="text/javascript">' . "\n";
174
- echo "alert('ERROR: Unable to modify subscription. Please contact Support for assistance.\\n\\nCould not get the existing user_id from the DB.');" . "\n";
175
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
176
  echo '</script>' . "\n";
177
- /**/
178
- $paypal["s2member_log"][] = "Redirecting Customer to the Login Page, due to an error that occurred.";
179
  }
180
  }
181
  else
182
  {
183
- $paypal["s2member_log"][] = "Unable to modify subscription. Could not find existing subscription in the DB. Please check the on0 and os0 variables in your Button Code.";
 
 
184
  /**/
185
  echo '<script type="text/javascript">' . "\n";
186
- echo "alert('ERROR: Unable to modify subscription. Please contact Support for assistance.\\n\\nCould not find existing subscription in the DB.');" . "\n";
187
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
188
  echo '</script>' . "\n";
189
- /**/
190
- $paypal["s2member_log"][] = "Redirecting Customer to the Login Page, due to an error that occurred.";
191
  }
192
  /**/
193
  do_action ("s2member_during_paypal_return_after_subscr_signup_w_update_vars");
194
  }
195
  /*
196
- New subscription. Normal subscription signup, we are not updating anything for a past subscription.
197
  */
198
- else /* Else this is a normal subscription signup, we are not updating anything for a past subscription. */
199
  {
200
  do_action ("s2member_during_paypal_return_before_subscr_signup_wo_update_vars");
201
  /**/
 
 
202
  $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept|subscr_signup|subscr_payment) w/o update vars.";
203
  /**/
204
  setcookie ("s2member_subscr_id", ws_plugin__s2member_encrypt ($paypal["subscr_id"]), time () + 31556926, "/");
205
  setcookie ("s2member_custom", ws_plugin__s2member_encrypt ($paypal["custom"]), time () + 31556926, "/");
206
  setcookie ("s2member_level", ws_plugin__s2member_encrypt ($paypal["item_number"]), time () + 31556926, "/");
207
  /**/
208
- $paypal["s2member_log"][] = "s2Member cookies set on (web_accept|subscr_signup|subscr_payment) w/o update vars.";
209
  /**/
210
  do_action ("s2member_during_paypal_return_during_subscr_signup_wo_update_vars");
211
  /**/
212
- echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "\n";
213
- echo '<html xmlns="http://www.w3.org/1999/xhtml" ', language_attributes (), '>' . "\n";
214
- echo '<head profile="http://gmpg.org/xfn/11">' . "\n";
215
- echo '<meta http-equiv="Content-Type" content="' . get_bloginfo ("html_type") . '; charset=' . get_bloginfo ("charset") . '" />' . "\n";
216
- echo '<script type="text/javascript">' . "\n"; /* Onload allows any tracking codes to finish loading. */
217
- echo "window.onload = function(){ " . "\n"; /* After everything has finished loading, we alert and then redirect. */
218
  echo "alert('Thank You! Your account has been approved.\\nThe next step is to Register a Username.\\n\\nPlease click OK to Register now.');" . "\n";/**/
219
- echo "window.location = '" . esc_js (add_query_arg ("action", "register", wp_login_url ())) . "'; };" . "\n";
220
  echo '</script>' . "\n";
221
- echo '</head>' . "\n";
222
- /**/
223
- echo '<body style="background:#' . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_background_color"] . ' url(' . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_background_image"] . ');">' . "\n";
224
- /**/
225
- echo '<!-- Tracking codes from the s2Member plugin for WordPress. -->' . "\n";
226
- /**/
227
- if (($code = trim ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_tracking_codes"])) && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
228
- {
229
- if (preg_match ("/^subscr_signup$/i", $paypal["txn_type"]))
230
- $initial = (isset ($paypal["mc_amount1"]) && preg_match ("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
231
- /* The initial amount will only be $0 if a trial was offered. If no trial was offered, they were charged a regular rate. */
232
- else if (preg_match ("/^(web_accept|subscr_payment)$/i", $paypal["txn_type"])) /* PDT w/Auto-Return sends subscr_payment. */
233
- $initial = $paypal["mc_gross"]; /* Here, the initial payment is provided clearly as the payment gross. */
234
- /**/
235
- if (($code = preg_replace ("/%%cv([0-9]+)%%/ei", 'trim($cv[$1])', $code)) && ($code = preg_replace ("/%%subscr_id%%/i", $paypal["subscr_id"], $code)))
236
- if (($code = preg_replace ("/%%initial%%/i", $initial, $code))) /* Adv calculations here. We have to support both sets of variables, subscr_signup & subscr_payment. */
237
- if (($code = preg_replace ("/%%item_number%%/i", $paypal["item_number"], $code)) && ($code = preg_replace ("/%%item_name%%/i", $paypal["item_name"], $code)))
238
- if (($code = preg_replace ("/%%first_name%%/i", $paypal["first_name"], $code)) && ($code = preg_replace ("/%%last_name%%/i", $paypal["last_name"], $code)))
239
- if (($code = preg_replace ("/%%full_name%%/i", trim ($paypal["first_name"] . " " . $paypal["last_name"]), $code)))
240
- if (($code = preg_replace ("/%%payer_email%%/i", $paypal["payer_email"], $code)))
241
- /**/
242
- if (($code = trim ($code))) /* Make sure it is not empty. */
243
- /**/
244
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["is_wpmu"])
245
- {
246
- echo $code . "\n"; /* No PHP allowed here. */
247
- $paypal["s2member_log"][] = "Signup Tracking codes have been processed.";
248
- }
249
- else /* Otherwise, it's safe to allow PHP code. */
250
- {
251
- eval ("?>" . $code);
252
- $paypal["s2member_log"][] = "Signup Tracking codes have been evaluated.";
253
- }
254
- }
255
- /**/
256
- echo '<!-- Tracking codes from the s2Member plugin for WordPress. -->' . "\n";
257
- /**/
258
- $paypal["s2member_log"][] = "Success! Redirecting Customer to Registration Page. They need to register a Username now.";
259
- /**/
260
- echo '</body>' . "\n";
261
- echo '</html>';
262
  /**/
263
  do_action ("s2member_during_paypal_return_after_subscr_signup_wo_update_vars");
264
  }
@@ -268,7 +211,7 @@ function ws_plugin__s2member_paypal_return ()
268
  /*
269
  Subscription modifications.
270
  */
271
- else if (preg_match ("/^subscr_modify$/i", $paypal["txn_type"]) && $paypal["subscr_id"] && preg_match ("/^[1-4](\:|$)/", $paypal["item_number"]))
272
  {
273
  do_action ("s2member_during_paypal_return_before_subscr_modify");
274
  /**/
@@ -276,11 +219,14 @@ function ws_plugin__s2member_paypal_return ()
276
  /**/
277
  list ($paypal["level"], $paypal["ccaps"]) = preg_split ("/\:/", $paypal["item_number"], 2);
278
  /**/
279
- if ($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = 's2member_subscr_id' AND `meta_value` = '" . $wpdb->escape ($paypal["subscr_id"]) . "' LIMIT 1"))
280
  {
281
- if ($user_id = $q->user_id) /* Got it! */
 
 
282
  {
283
- $user = new WP_User ($user_id);
 
284
  $user->set_role ("s2member_level" . $paypal["level"]);
285
  update_usermeta ($user_id, "s2member_subscr_id", $paypal["subscr_id"]);
286
  update_usermeta ($user_id, "s2member_custom", $paypal["custom"]);
@@ -295,40 +241,43 @@ function ws_plugin__s2member_paypal_return ()
295
  /**/
296
  delete_usermeta ($user_id, "s2member_file_download_access_arc");
297
  delete_usermeta ($user_id, "s2member_file_download_access_log");
 
 
 
298
  /**/
299
- $paypal["s2member_log"][] = "s2Member Level/Capabilities updated on subscription modification.";
300
  /**/
301
  do_action ("s2member_during_paypal_return_during_subscr_modify");
302
  /**/
 
 
303
  echo '<script type="text/javascript">' . "\n";
304
  echo "alert('Thank You! Your membership has been updated to:\\n\\n" . esc_js ($paypal["item_name"]) . "\\n\\nYou\\'ll need to log back in now.');" . "\n";
305
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
306
  echo '</script>' . "\n";
307
- /**/
308
- $paypal["s2member_log"][] = "Success! Redirecting Customer to the Login Page. They need to log back in after this modification.";
309
  }
310
  else
311
  {
312
- $paypal["s2member_log"][] = "Unable to modify subscription. Could not get the existing user_id from the DB.";
 
 
313
  /**/
314
  echo '<script type="text/javascript">' . "\n";
315
- echo "alert('ERROR: Unable to modify subscription. Please contact Support for assistance.\\n\\nCould not get the existing user_id from the DB.');" . "\n";
316
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
317
  echo '</script>' . "\n";
318
- /**/
319
- $paypal["s2member_log"][] = "Redirecting Customer to the Login Page, due to an error that occurred.";
320
  }
321
  }
322
  else
323
  {
324
- $paypal["s2member_log"][] = "Unable to modify subscription. Could not find existing subscription in the DB.";
 
 
325
  /**/
326
  echo '<script type="text/javascript">' . "\n";
327
- echo "alert('ERROR: Unable to modify subscription. Please contact Support for assistance.\\n\\nCould not find existing subscription in the DB.');" . "\n";
328
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
329
  echo '</script>' . "\n";
330
- /**/
331
- $paypal["s2member_log"][] = "Redirecting Customer to the Login Page, due to an error that occurred.";
332
  }
333
  /**/
334
  do_action ("s2member_during_paypal_return_after_subscr_modify");
@@ -337,49 +286,54 @@ function ws_plugin__s2member_paypal_return ()
337
  {
338
  $paypal["s2member_log"][] = "Unexpected txn_type. The PayPal® txn_type did not match a required action.";
339
  /**/
 
 
340
  echo '<script type="text/javascript">' . "\n";
341
  echo "alert('ERROR: Unexpected txn_type. Please contact Support for assistance.\\n\\nThe PayPal® txn_type did not match a required action.');" . "\n";
342
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
343
  echo '</script>' . "\n";
344
- /**/
345
- $paypal["s2member_log"][] = "Redirecting Customer to the Login Page, due to an error that occurred.";
346
  }
347
  }
348
  else
349
  {
350
  $paypal["s2member_log"][] = "Unable to verify _SERVER[HTTP_HOST]. Please check the `custom` value in your Button Code. It MUST start with your domain name.";
351
  /**/
 
 
352
  echo '<script type="text/javascript">' . "\n";
353
  echo "alert('ERROR: Unable to verify _SERVER[HTTP_HOST]. Please contact Support for assistance.\\n\\nIf you are the site owner, please check the `custom` value in your Button Code. It MUST start with your domain name.');" . "\n";
354
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
355
  echo '</script>' . "\n";
356
- /**/
357
- $paypal["s2member_log"][] = "Redirecting Customer to the Login Page, due to an error that occurred.";
358
  }
359
  }
360
  else if (!isset ($_GET["tx"]) && (empty ($_POST) || $_POST["auth"]))
361
  {
 
 
362
  $paypal["s2member_log"][] = "No Return-Data from PayPal®. Customer must wait for Email Confirmation.";
363
  /**/
 
 
 
 
364
  echo '<script type="text/javascript">' . "\n";
365
  echo "alert('Thank You! ( please check your email ).\\n\\n* Note: It can take ( up to 15 minutes ) for Email Confirmation. If you don\'t receive email confirmation in the next 15 minutes, please contact Support.');" . "\n";
366
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"])
367
- echo "alert('** Sandbox Mode ** You will probably NOT receive this Email Confirmation in Sandbox Mode. Sandbox addresses are usually bogus ( for testing ).');" . "\n";
368
  echo "window.location = '" . esc_js (get_bloginfo ("url")) . "';";
369
  echo '</script>' . "\n";
370
  /**/
371
- $paypal["s2member_log"][] = "Redirecting Customer to the Home Page.";
372
  }
373
  else
374
  {
375
  $paypal["s2member_log"][] = "Unable to verify POST vars. This is most likely related to an invalid PayPal® configuration. Please check: s2Member -> PayPal® Options.";
376
  /**/
 
 
377
  echo '<script type="text/javascript">' . "\n";
378
  echo "alert('ERROR: Unable to verify POST vars. Please contact Support for assistance.\\n\\nThis is most likely related to an invalid PayPal® configuration. If you are the site owner, please check: s2Member -> PayPal® Options.');" . "\n";
379
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
380
  echo '</script>' . "\n";
381
- /**/
382
- $paypal["s2member_log"][] = "Redirecting Customer to the Login Page, due to an error that occurred.";
383
  }
384
  /**/
385
  if ($_GET["s2member_paypal_proxy"]) /* For proxy identification. */
14
  if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
  exit;
16
  /*
17
+ Handles PayPal® Return URL processing.
18
  Attach to: add_action("init");
19
  */
20
  function ws_plugin__s2member_paypal_return ()
23
  /**/
24
  if ($_GET["s2member_paypal_return"] && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"])
25
  {
26
+ if (is_array ($paypal = ws_plugin__s2member_paypal_postvars ())) /* Verify PayPal® POST vars. */
 
 
27
  {
28
+ $paypal["s2member_log"][] = "Return-Data received on: " . date ("D M j, Y g:i:s a T");
29
  $paypal["s2member_log"][] = "s2Member POST vars verified through a POST back to PayPal®.";
30
  /**/
31
  if (preg_match ("/^" . preg_quote ($_SERVER["HTTP_HOST"], "/") . "/i", $paypal["custom"])) /* Matches originating host? */
32
  { /* The business address validation was removed from this routine, because PayPal® always fills that with the primary
33
+ email address. In cases where an alternate PayPal® address is being paid, validation was not possible. */
34
  $paypal["s2member_log"][] = "s2Member originating domain ( _SERVER[HTTP_HOST] ) validated.";
35
  /*
36
+ Specific Post/Page Access.
37
  */
38
+ if (preg_match ("/^web_accept$/i", $paypal["txn_type"]) && $paypal["txn_id"] && preg_match ("/^sp\:[0-9,]+\:[0-9]+$/", $paypal["item_number"]))
39
  {
40
  do_action ("s2member_during_paypal_return_before_sp_access");
41
  /**/
42
+ $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept) for Specific Post/Page access.";
43
  /**/
44
+ list (, $paypal["sp_ids"], $paypal["hours"]) = preg_split ("/\:/", $paypal["item_number"], 3);
45
  /**/
46
+ if (($sp_access_url = ws_plugin__s2member_sp_access_link_gen ($paypal["sp_ids"], $paypal["hours"], false)))
47
  {
48
+ $processing = $during = true; /* Yes, we ARE processing this. */
49
+ /**/
50
+ setcookie ("s2member_sp_tracking", ws_plugin__s2member_encrypt ($paypal["txn_id"]), time () + 31556926, "/");
51
+ /**/
52
+ $paypal["s2member_log"][] = "Transient Tracking Cookie set on (web_accept) for Specific Post/Page Access.";
53
+ /**/
54
+ if ($processing && ($code = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_tracking_codes"]) && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
55
+ {
56
+ if (($code = preg_replace ("/%%cv([0-9]+)%%/ei", 'trim($cv[$1])', $code)) && ($code = preg_replace ("/%%amount%%/i", $paypal["mc_gross"], $code)) && ($code = preg_replace ("/%%txn_id%%/i", $paypal["txn_id"], $code)))
57
+ if (($code = preg_replace ("/%%item_number%%/i", $paypal["item_number"], $code)) && ($code = preg_replace ("/%%item_name%%/i", $paypal["item_name"], $code)))
58
+ if (($code = preg_replace ("/%%first_name%%/i", $paypal["first_name"], $code)) && ($code = preg_replace ("/%%last_name%%/i", $paypal["last_name"], $code)))
59
+ if (($code = preg_replace ("/%%full_name%%/i", trim ($paypal["first_name"] . " " . $paypal["last_name"]), $code)))
60
+ if (($code = preg_replace ("/%%payer_email%%/i", $paypal["payer_email"], $code)))
61
+ /**/
62
+ if (($code = trim ($code))) /* Make sure it is not empty. This gets stored into a Transient Queue. */
63
+ {
64
+ $paypal["s2member_log"][] = "Storing Specific Post/Page Tracking Codes into a Transient Queue for s2Member. These will be processed on-site.";
65
+ set_transient (md5 ("s2member_transient_sp_tracking_codes_" . $paypal["txn_id"]), $code, 43200);
66
+ }
67
+ }
68
  /**/
69
  do_action ("s2member_during_paypal_return_during_sp_access");
70
  /**/
71
+ $paypal["s2member_log"][] = "Redirecting Customer to the Specific Post/Page.";
72
+ /**/
73
  header ("Location: " . $sp_access_url);
74
  }
75
+ else /* Otherwise, the ID must have been invalid. Or the Post/Page was deleted. */
76
  {
77
+ $paypal["s2member_log"][] = "Unable to generate Specific Post/Page Access Link. Does your Leading Post/Page still exist?";
78
+ /**/
79
+ $paypal["s2member_log"][] = "Redirecting Customer to the Home Page, due to an error that occurred.";
80
  /**/
81
  echo '<script type="text/javascript">' . "\n";
82
  echo "alert('ERROR: Unable to generate Access Link. Please contact Support for assistance.');" . "\n";
83
  echo "window.location = '" . esc_js (get_bloginfo ("url")) . "';";
84
  echo '</script>' . "\n";
 
 
85
  }
86
  /**/
87
  do_action ("s2member_during_paypal_return_after_sp_access");
88
  }
89
  /*
90
+ New Subscriptions. Possibly containing advanced updated vars ( option_name1, option_selection1 ); which allow account modifications.
91
  */
92
+ else if (preg_match ("/^(web_accept|subscr_signup|subscr_payment)$/i", $paypal["txn_type"]) && ($paypal["subscr_id"] || ($paypal["subscr_id"] = $paypal["txn_id"])) && preg_match ("/^[1-4](\:|$)([a-z_0-9,]+)?(\:)?([0-9] [A-Z])?$/", $paypal["item_number"]))
93
  { /* With Auto-Return/PDT, PayPal will send subscr_payment instead of subscr_signup to the return URL.
94
  So we need to look for (web_accept|subscr_signup|subscr_payment), and treat them as the same. */
95
  /**/
97
  /**/
98
  $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept|subscr_signup|subscr_payment).";
99
  /**/
100
+ list ($paypal["level"], $paypal["ccaps"], $paypal["eotper"]) = preg_split ("/\:/", $paypal["item_number"], 3);
101
  /*
102
+ New Subscription with advanced update vars ( option_name1, option_selection1 ).
103
  */
104
+ if (preg_match ("/(updat|upgrad)/i", $paypal["option_name1"]) && $paypal["option_selection1"]) /* Advanced Subscription update modifications. */
105
+ /* This advanced method is required whenever a Subscription that is already completed, or was never setup to recur in the first place needs to be modified. PayPal® will not allow the
106
+ modify=2 parameter to be used in those scenarios, because technically there is nothing to update. The only thing to be updated is the account. */
107
  {
108
  do_action ("s2member_during_paypal_return_before_subscr_signup_w_update_vars");
109
  /**/
110
  $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept|subscr_signup|subscr_payment) w/ update vars.";
111
  /**/
112
+ /* Check for both the old & new subscr_id's, just in case the IPN routine already changed it. */
113
+ if (($user_id = ws_plugin__s2member_paypal_user_id ($paypal["subscr_id"], $paypal["option_selection1"])))
 
114
  {
115
+ $user = new WP_User ($user_id); /* Acquire user object. */
116
+ /**/
117
+ if (!ws_plugin__s2member_user_has_wp_role ($user)) /* Non WP Roles. */
118
  {
119
+ $processing = $during = true; /* Yes, we ARE processing this. */
120
+ /**/
121
  $user->set_role ("s2member_level" . $paypal["level"]);
122
  update_usermeta ($user_id, "s2member_subscr_id", $paypal["subscr_id"]);
123
  update_usermeta ($user_id, "s2member_custom", $paypal["custom"]);
133
  delete_usermeta ($user_id, "s2member_file_download_access_arc");
134
  delete_usermeta ($user_id, "s2member_file_download_access_log");
135
  /**/
136
+ if (preg_match ("/^web_accept$/i", $paypal["txn_type"]) && $paypal["eotper"])
137
+ update_usermeta ($user_id, "s2member_auto_eot_time", ws_plugin__s2member_paypal_auto_eot_time (0, 0, 0, $paypal["eotper"]));
138
+ else /* Otherwise, we need to clear the eot time. */
139
+ delete_usermeta ($user_id, "s2member_auto_eot_time");
140
+ /**/
141
+ ws_plugin__s2member_clear_user_note_lines ($user_id, "/^Demoted by s2Member\:/");
142
+ /**/
143
  $paypal["s2member_log"][] = "s2Member Level/Capabilities updated w/ advanced update routines.";
144
  /**/
145
  do_action ("s2member_during_paypal_return_during_subscr_signup_w_update_vars");
146
  /**/
147
+ $paypal["s2member_log"][] = "Redirecting Customer to the Login Page. They need to log back in after this modification.";
148
+ /**/
149
+ echo '<script type="text/javascript">' . "\n";
 
 
 
150
  echo "alert('Thank You! Your membership has been updated to:\\n\\n" . esc_js ($paypal["item_name"]) . "\\n\\nYou\\'ll need to log back in now.');" . "\n";
151
+ echo "window.location = '" . wp_login_url () . "';" . "\n";
152
  echo '</script>' . "\n";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  }
154
  else
155
  {
156
+ $paypal["s2member_log"][] = "Unable to modify Subscription. The existing User ID has a built-in WP Role. Stopping here. Otherwise, an Administrator/Editor/Author/Contributor could lose access.";
157
+ /**/
158
+ $paypal["s2member_log"][] = "Redirecting Customer to the Login Page, due to an error that occurred.";
159
  /**/
160
  echo '<script type="text/javascript">' . "\n";
161
+ echo "alert('ERROR: Unable to modify Subscription. Please contact Support for assistance.\\n\\nThe existing User ID has a built-in WP Role. Stopping here. Otherwise, an Administrator/Editor/Author/Contributor could lose access. Please make sure that you are NOT logged in as an Administrator/Editor/Author/Contributor while testing.');" . "\n";
162
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
163
  echo '</script>' . "\n";
 
 
164
  }
165
  }
166
  else
167
  {
168
+ $paypal["s2member_log"][] = "Unable to modify Subscription. Could not get the existing User ID from the DB. Please check the on0 and os0 variables in your Button Code.";
169
+ /**/
170
+ $paypal["s2member_log"][] = "Redirecting Customer to the Login Page, due to an error that occurred.";
171
  /**/
172
  echo '<script type="text/javascript">' . "\n";
173
+ echo "alert('ERROR: Unable to modify Subscription. Please contact Support for assistance.\\n\\nCould not get the existing User ID from the DB.');" . "\n";
174
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
175
  echo '</script>' . "\n";
 
 
176
  }
177
  /**/
178
  do_action ("s2member_during_paypal_return_after_subscr_signup_w_update_vars");
179
  }
180
  /*
181
+ New Subscription. Normal Subscription signup, we are not updating anything for a past Subscription.
182
  */
183
+ else /* Else this is a normal Subscription signup, we are not updating an existing Subscription. */
184
  {
185
  do_action ("s2member_during_paypal_return_before_subscr_signup_wo_update_vars");
186
  /**/
187
+ $processing = $during = true; /* Yes, we ARE processing this new Subscription request. */
188
+ /**/
189
  $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept|subscr_signup|subscr_payment) w/o update vars.";
190
  /**/
191
  setcookie ("s2member_subscr_id", ws_plugin__s2member_encrypt ($paypal["subscr_id"]), time () + 31556926, "/");
192
  setcookie ("s2member_custom", ws_plugin__s2member_encrypt ($paypal["custom"]), time () + 31556926, "/");
193
  setcookie ("s2member_level", ws_plugin__s2member_encrypt ($paypal["item_number"]), time () + 31556926, "/");
194
  /**/
195
+ $paypal["s2member_log"][] = "Registration Cookies set on (web_accept|subscr_signup|subscr_payment) w/o update vars.";
196
  /**/
197
  do_action ("s2member_during_paypal_return_during_subscr_signup_wo_update_vars");
198
  /**/
199
+ $paypal["s2member_log"][] = "Redirecting Customer to Registration Page. They need to register a Username now.";
200
+ /**/
201
+ echo '<script type="text/javascript">' . "\n";
 
 
 
202
  echo "alert('Thank You! Your account has been approved.\\nThe next step is to Register a Username.\\n\\nPlease click OK to Register now.');" . "\n";/**/
203
+ echo "window.location = '" . esc_js (add_query_arg ("action", "register", wp_login_url ())) . "';" . "\n";
204
  echo '</script>' . "\n";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  /**/
206
  do_action ("s2member_during_paypal_return_after_subscr_signup_wo_update_vars");
207
  }
211
  /*
212
  Subscription modifications.
213
  */
214
+ else if (preg_match ("/^subscr_modify$/i", $paypal["txn_type"]) && $paypal["subscr_id"] && preg_match ("/^[1-4](\:|$)([a-z_0-9,]+)?(\:)?([0-9] [A-Z])?$/", $paypal["item_number"]))
215
  {
216
  do_action ("s2member_during_paypal_return_before_subscr_modify");
217
  /**/
219
  /**/
220
  list ($paypal["level"], $paypal["ccaps"]) = preg_split ("/\:/", $paypal["item_number"], 2);
221
  /**/
222
+ if (($user_id = ws_plugin__s2member_paypal_user_id ($paypal["subscr_id"])))
223
  {
224
+ $user = new WP_User ($user_id); /* Acquire user object. */
225
+ /**/
226
+ if (!ws_plugin__s2member_user_has_wp_role ($user)) /* Non WP Roles. */
227
  {
228
+ $processing = $during = true; /* Yes, we ARE processing this. */
229
+ /**/
230
  $user->set_role ("s2member_level" . $paypal["level"]);
231
  update_usermeta ($user_id, "s2member_subscr_id", $paypal["subscr_id"]);
232
  update_usermeta ($user_id, "s2member_custom", $paypal["custom"]);
241
  /**/
242
  delete_usermeta ($user_id, "s2member_file_download_access_arc");
243
  delete_usermeta ($user_id, "s2member_file_download_access_log");
244
+ delete_usermeta ($user_id, "s2member_auto_eot_time");
245
+ /**/
246
+ ws_plugin__s2member_clear_user_note_lines ($user_id, "/^Demoted by s2Member\:/");
247
  /**/
248
+ $paypal["s2member_log"][] = "s2Member Level/Capabilities updated on Subscription modification.";
249
  /**/
250
  do_action ("s2member_during_paypal_return_during_subscr_modify");
251
  /**/
252
+ $paypal["s2member_log"][] = "Redirecting Customer to the Login Page. They need to log back in after this modification.";
253
+ /**/
254
  echo '<script type="text/javascript">' . "\n";
255
  echo "alert('Thank You! Your membership has been updated to:\\n\\n" . esc_js ($paypal["item_name"]) . "\\n\\nYou\\'ll need to log back in now.');" . "\n";
256
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
257
  echo '</script>' . "\n";
 
 
258
  }
259
  else
260
  {
261
+ $paypal["s2member_log"][] = "Unable to modify Subscription. The existing User ID has a built-in WP Role. Stopping here. Otherwise, an Administrator/Editor/Author/Contributor could lose access.";
262
+ /**/
263
+ $paypal["s2member_log"][] = "Redirecting Customer to the Login Page, due to an error that occurred.";
264
  /**/
265
  echo '<script type="text/javascript">' . "\n";
266
+ echo "alert('ERROR: Unable to modify Subscription. Please contact Support for assistance.\\n\\nThe existing User ID has a built-in WP Role. Stopping here. Otherwise, an Administrator/Editor/Author/Contributor could lose access. Please make sure that you are NOT logged in as an Administrator/Editor/Author/Contributor while testing.');" . "\n";
267
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
268
  echo '</script>' . "\n";
 
 
269
  }
270
  }
271
  else
272
  {
273
+ $paypal["s2member_log"][] = "Unable to modify Subscription. Could not get the existing User ID from the DB.";
274
+ /**/
275
+ $paypal["s2member_log"][] = "Redirecting Customer to the Login Page, due to an error that occurred.";
276
  /**/
277
  echo '<script type="text/javascript">' . "\n";
278
+ echo "alert('ERROR: Unable to modify Subscription. Please contact Support for assistance.\\n\\nCould not get the existing User ID from the DB.');" . "\n";
279
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
280
  echo '</script>' . "\n";
 
 
281
  }
282
  /**/
283
  do_action ("s2member_during_paypal_return_after_subscr_modify");
286
  {
287
  $paypal["s2member_log"][] = "Unexpected txn_type. The PayPal® txn_type did not match a required action.";
288
  /**/
289
+ $paypal["s2member_log"][] = "Redirecting Customer to the Login Page, due to an error that occurred.";
290
+ /**/
291
  echo '<script type="text/javascript">' . "\n";
292
  echo "alert('ERROR: Unexpected txn_type. Please contact Support for assistance.\\n\\nThe PayPal® txn_type did not match a required action.');" . "\n";
293
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
294
  echo '</script>' . "\n";
 
 
295
  }
296
  }
297
  else
298
  {
299
  $paypal["s2member_log"][] = "Unable to verify _SERVER[HTTP_HOST]. Please check the `custom` value in your Button Code. It MUST start with your domain name.";
300
  /**/
301
+ $paypal["s2member_log"][] = "Redirecting Customer to the Login Page, due to an error that occurred.";
302
+ /**/
303
  echo '<script type="text/javascript">' . "\n";
304
  echo "alert('ERROR: Unable to verify _SERVER[HTTP_HOST]. Please contact Support for assistance.\\n\\nIf you are the site owner, please check the `custom` value in your Button Code. It MUST start with your domain name.');" . "\n";
305
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
306
  echo '</script>' . "\n";
 
 
307
  }
308
  }
309
  else if (!isset ($_GET["tx"]) && (empty ($_POST) || $_POST["auth"]))
310
  {
311
+ do_action ("s2member_during_paypal_return_before_no_return_data");
312
+ /**/
313
  $paypal["s2member_log"][] = "No Return-Data from PayPal®. Customer must wait for Email Confirmation.";
314
  /**/
315
+ do_action ("s2member_during_paypal_return_during_no_return_data");
316
+ /**/
317
+ $paypal["s2member_log"][] = "Redirecting Customer to the Home Page.";
318
+ /**/
319
  echo '<script type="text/javascript">' . "\n";
320
  echo "alert('Thank You! ( please check your email ).\\n\\n* Note: It can take ( up to 15 minutes ) for Email Confirmation. If you don\'t receive email confirmation in the next 15 minutes, please contact Support.');" . "\n";
321
+ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "alert('** Sandbox Mode ** You will probably NOT receive this Email Confirmation in Sandbox Mode. Sandbox addresses are usually bogus ( for testing ).');" . "\n" : "";
 
322
  echo "window.location = '" . esc_js (get_bloginfo ("url")) . "';";
323
  echo '</script>' . "\n";
324
  /**/
325
+ do_action ("s2member_during_paypal_return_after_no_return_data");
326
  }
327
  else
328
  {
329
  $paypal["s2member_log"][] = "Unable to verify POST vars. This is most likely related to an invalid PayPal® configuration. Please check: s2Member -> PayPal® Options.";
330
  /**/
331
+ $paypal["s2member_log"][] = "Redirecting Customer to the Login Page, due to an error that occurred.";
332
+ /**/
333
  echo '<script type="text/javascript">' . "\n";
334
  echo "alert('ERROR: Unable to verify POST vars. Please contact Support for assistance.\\n\\nThis is most likely related to an invalid PayPal® configuration. If you are the site owner, please check: s2Member -> PayPal® Options.');" . "\n";
335
  echo "window.location = '" . esc_js (wp_login_url ()) . "';";
336
  echo '</script>' . "\n";
 
 
337
  }
338
  /**/
339
  if ($_GET["s2member_paypal_proxy"]) /* For proxy identification. */
includes/functions/paypal-utilities.inc.php ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright: © 2009 WebSharks, Inc. ( coded in the USA )
4
+ <mailto:support@websharks-inc.com> <http://www.websharks-inc.com/>
5
+
6
+ Released under the terms of the GNU General Public License.
7
+ You should have received a copy of the GNU General Public License,
8
+ along with this software. In the main directory, see: /licensing/
9
+ If not, see: <http://www.gnu.org/licenses/>.
10
+ */
11
+ /*
12
+ Direct access denial.
13
+ */
14
+ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
+ exit;
16
+ /*
17
+ Get POST vars from PayPal®, verify and return array.
18
+ */
19
+ function ws_plugin__s2member_paypal_postvars ()
20
+ {
21
+ do_action ("s2member_before_paypal_postvars");
22
+ /**/
23
+ if ($_GET["tx"]) /* PDT with Auto-Return. */
24
+ {
25
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_identity_token"])
26
+ {
27
+ $postback = "cmd=_notify-synch";
28
+ /**/
29
+ $postback .= "&tx=" . urlencode ($_GET["tx"]);
30
+ $postback .= "&at=" . urlencode ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_identity_token"]);
31
+ /**/
32
+ $endpoint = ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com";
33
+ /**/
34
+ if (preg_match ("/^SUCCESS/i", ($response = trim (ws_plugin__s2member_curlpsr ("https://" . $endpoint . "/cgi-bin/webscr", $postback)))))
35
+ {
36
+ foreach (preg_split ("/[\r\n]+/", preg_replace ("/^SUCCESS/i", "", $response)) as $varline)
37
+ {
38
+ list ($key, $value) = preg_split ("/\=/", $varline, 2);
39
+ if (strlen ($key = trim ($key)) && strlen ($value = trim ($value)))
40
+ $postvars[$key] = trim (stripslashes (urldecode ($value)));
41
+ }
42
+ /**/
43
+ return apply_filters ("s2member_paypal_postvars", $postvars);
44
+ }
45
+ }
46
+ /**/
47
+ return false;
48
+ }
49
+ else if (is_array ($postvars = stripslashes_deep ($_POST)))
50
+ {
51
+ $postback = "cmd=_notify-validate";
52
+ /**/
53
+ foreach ($postvars as $key => $value)
54
+ $postback .= "&" . $key . "=" . urlencode ($value);
55
+ /**/
56
+ foreach ($postvars as $key => $value)
57
+ $postvars[$key] = trim ($value);
58
+ /**/
59
+ $endpoint = ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com";
60
+ /**/
61
+ if (strtolower (trim (ws_plugin__s2member_curlpsr ("https://" . $endpoint . "/cgi-bin/webscr", $postback))) === "verified")
62
+ {
63
+ return apply_filters ("s2member_paypal_postvars", $postvars);
64
+ }
65
+ /**/
66
+ return false;
67
+ }
68
+ else /* Unable to obtain. */
69
+ {
70
+ return false;
71
+ }
72
+ }
73
+ /*
74
+ Get the custom value for an existing Member, referenced by a Subscr. ID.
75
+ */
76
+ function ws_plugin__s2member_paypal_custom ($subscr_id = FALSE, $os0 = FALSE)
77
+ {
78
+ global $wpdb; /* Need global DB obj. */
79
+ /**/
80
+ do_action ("s2member_before_paypal_custom");
81
+ /**/
82
+ if ($subscr_id && $os0) /* This case includes some additional routines that can use the $os0 value. */
83
+ {
84
+ if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = 's2member_subscr_id' AND (`meta_value` = '" . $wpdb->escape ($subscr_id) . "' OR `meta_value` = '" . $wpdb->escape ($os0) . "') LIMIT 1"))/**/
85
+ || ($q = $wpdb->get_row ("SELECT `ID` AS `user_id` FROM `" . $wpdb->users . "` WHERE `ID` = '" . $wpdb->escape ($os0) . "' LIMIT 1")))
86
+ if (($custom = get_usermeta ($q->user_id, "s2member_custom")))
87
+ return apply_filters ("s2member_paypal_custom", $custom);
88
+ }
89
+ else if ($subscr_id) /* Otherwise, if all we have is a Subscr. ID value. */
90
+ {
91
+ if ($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = 's2member_subscr_id' AND `meta_value` = '" . $wpdb->escape ($subscr_id) . "' LIMIT 1"))
92
+ if (($custom = get_usermeta ($q->user_id, "s2member_custom")))
93
+ return apply_filters ("s2member_paypal_custom", $custom);
94
+ }
95
+ /**/
96
+ return apply_filters ("s2member_paypal_custom", false);
97
+ }
98
+ /*
99
+ Get the user ID for an existing Member, referenced by a Subscr. ID.
100
+ A second lookup parameter can be provided, which will trigger some additional routines.
101
+ The $os0 value comes from advanced update vars, pertaining to subscription modifications.
102
+ */
103
+ function ws_plugin__s2member_paypal_user_id ($subscr_id = FALSE, $os0 = FALSE)
104
+ {
105
+ global $wpdb; /* Need global DB obj. */
106
+ /**/
107
+ do_action ("s2member_before_paypal_user_id");
108
+ /**/
109
+ if ($subscr_id && $os0) /* This case includes some additional routines that can use the $os0 value. */
110
+ {
111
+ if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = 's2member_subscr_id' AND (`meta_value` = '" . $wpdb->escape ($subscr_id) . "' OR `meta_value` = '" . $wpdb->escape ($os0) . "') LIMIT 1"))/**/
112
+ || ($q = $wpdb->get_row ("SELECT `ID` AS `user_id` FROM `" . $wpdb->users . "` WHERE `ID` = '" . $wpdb->escape ($os0) . "' LIMIT 1")))
113
+ return apply_filters ("s2member_paypal_user_id", $q->user_id);
114
+ }
115
+ else if ($subscr_id) /* Otherwise, if all we have is a Subscr. ID value. */
116
+ {
117
+ if ($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = 's2member_subscr_id' AND `meta_value` = '" . $wpdb->escape ($subscr_id) . "' LIMIT 1"))
118
+ return apply_filters ("s2member_paypal_user_id", $q->user_id);
119
+ }
120
+ /**/
121
+ return apply_filters ("s2member_paypal_user_id", false);
122
+ }
123
+ /*
124
+ Calculate Auto-EOT Time, based on last_payment_time, period1, and period3.
125
+ This is used by s2Member's built-in Auto-EOT System, and by its IPN routines.
126
+ */
127
+ function ws_plugin__s2member_paypal_auto_eot_time ($user_id = FALSE, $period1 = FALSE, $period3 = FALSE, $eotper = FALSE)
128
+ {
129
+ do_action ("s2member_before_paypal_auto_eot_time");
130
+ /**/
131
+ if ($user_id && ($user = new WP_User ($user_id))) /* Must have a valid user_id. */
132
+ {
133
+ $registration_time = strtotime ($user->user_registered);
134
+ $last_payment_time = (int)get_usermeta ($user_id, "s2member_last_payment_time");
135
+ /**/
136
+ if (!($p1_time = 0) && ($period1 = trim (strtoupper ($period1))))
137
+ {
138
+ list ($num, $span) = preg_split ("/ /", $period1, 2);
139
+ /**/
140
+ $days = 0; /* Days start at 0. */
141
+ $days = ($span === "D") ? 1 : $days;
142
+ $days = ($span === "W") ? 7 : $days;
143
+ $days = ($span === "M") ? 30 : $days;
144
+ $days = ($span === "Y") ? 365 : $days;
145
+ /**/
146
+ $p1_days = (int)$num * (int)$days;
147
+ $p1_time = $p1_days * 86400;
148
+ }
149
+ /**/
150
+ if (!($p3_time = 0) && ($period3 = trim (strtoupper ($period3))))
151
+ {
152
+ list ($num, $span) = preg_split ("/ /", $period3, 2);
153
+ /**/
154
+ $days = 0; /* Days start at 0. */
155
+ $days = ($span === "D") ? 1 : $days;
156
+ $days = ($span === "W") ? 7 : $days;
157
+ $days = ($span === "M") ? 30 : $days;
158
+ $days = ($span === "Y") ? 365 : $days;
159
+ /**/
160
+ $p3_days = (int)$num * (int)$days;
161
+ $p3_time = $p3_days * 86400;
162
+ }
163
+ /**/
164
+ if (!$last_payment_time) /* If no payment yet.
165
+ EOT after p1, if there was a p1. Otherwise, now + 1 day grace. */
166
+ {
167
+ $auto_eot_time = $registration_time + $p1_time + 86400;
168
+ }
169
+ /* Else if p1, and last payment was within p1, last + p1 + 1 day grace. */
170
+ else if ($p1_time && $last_payment_time <= $registration_time + $p1_time)
171
+ {
172
+ $auto_eot_time = $last_payment_time + $p1_time + 86400;
173
+ }
174
+ else /* Otherwise, the EOT comes after last payment + p3 + 1 day grace. */
175
+ {
176
+ $auto_eot_time = $last_payment_time + $p3_time + 86400;
177
+ }
178
+ }
179
+ /**/
180
+ else if ($eotper) /* Otherwise, if we have a specific EOT period; calculate from today. */
181
+ {
182
+ if (!($eot_time = 0) && ($eotper = trim (strtoupper ($eotper))))
183
+ {
184
+ list ($num, $span) = preg_split ("/ /", $eotper, 2);
185
+ /**/
186
+ $days = 0; /* Days start at 0. */
187
+ $days = ($span === "D") ? 1 : $days;
188
+ $days = ($span === "W") ? 7 : $days;
189
+ $days = ($span === "M") ? 30 : $days;
190
+ $days = ($span === "Y") ? 365 : $days;
191
+ /**/
192
+ $eot_days = (int)$num * (int)$days;
193
+ $eot_time = $eot_days * 86400;
194
+ }
195
+ /**/
196
+ $auto_eot_time = strtotime ("now") + $eot_time + 86400;
197
+ }
198
+ /**/
199
+ $auto_eot_time = ($auto_eot_time <= 0) ? strtotime ("now") : $auto_eot_time;
200
+ /**/
201
+ return apply_filters ("s2member_paypal_auto_eot_time", $auto_eot_time);
202
+ }
203
+ ?>
includes/functions/post-level-access.inc.php CHANGED
@@ -31,28 +31,31 @@ function ws_plugin__s2member_check_post_level_access ()
31
  {
32
  $current_user = (is_user_logged_in ()) ? wp_get_current_user () : false;
33
  /**/
34
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_posts"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
35
  exit;
36
  /**/
37
- else if (in_array ($post_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_posts"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
38
  exit;
39
  /**/
40
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_posts"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=2")) !== "nill")
41
  exit;
42
  /**/
43
- else if (in_array ($post_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_posts"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=2")) !== "nill")
44
  exit;
45
  /**/
46
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_posts"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=3")) !== "nill")
47
  exit;
48
  /**/
49
- else if (in_array ($post_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_posts"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=3")) !== "nill")
50
  exit;
51
  /**/
52
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_posts"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=4")) !== "nill")
53
  exit;
54
  /**/
55
- else if (in_array ($post_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_posts"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=4")) !== "nill")
 
 
 
56
  exit;
57
  /**/
58
  do_action ("s2member_during_check_post_level_access");
31
  {
32
  $current_user = (is_user_logged_in ()) ? wp_get_current_user () : false;
33
  /**/
34
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_posts"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
35
  exit;
36
  /**/
37
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_posts"] && in_array ($post_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_posts"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
38
  exit;
39
  /**/
40
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_posts"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (add_query_arg ("s2member_level_req", "2", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
41
  exit;
42
  /**/
43
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_posts"] && in_array ($post_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_posts"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (add_query_arg ("s2member_level_req", "2", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
44
  exit;
45
  /**/
46
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_posts"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (add_query_arg ("s2member_level_req", "3", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
47
  exit;
48
  /**/
49
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_posts"] && in_array ($post_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_posts"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (add_query_arg ("s2member_level_req", "3", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
50
  exit;
51
  /**/
52
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_posts"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (add_query_arg ("s2member_level_req", "4", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
53
  exit;
54
  /**/
55
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_posts"] && in_array ($post_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_posts"])) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (add_query_arg ("s2member_level_req", "4", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
56
+ exit;
57
+ /**/
58
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["specific_ids"] && in_array ($post_ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["specific_ids"])) && ws_plugin__s2member_nocache_constants () !== "nill" && !ws_plugin__s2member_sp_access ($post_ID) && wp_redirect (add_query_arg ("s2member_sp_req", $post_ID, get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
59
  exit;
60
  /**/
61
  do_action ("s2member_during_check_post_level_access");
includes/functions/ptag-level-access.inc.php CHANGED
@@ -33,54 +33,54 @@ function ws_plugin__s2member_check_ptag_level_access ()
33
  /**/
34
  if (is_tag () && $tag_ID) /* We also check if this is a post or page with tags, having a restricted tag. */
35
  {
36
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_ptags"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
37
  exit;
38
  /**/
39
- else if (($level1_ptags = preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_ptags"]))) && is_tag ($level1_ptags) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
40
  exit;
41
  /**/
42
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_ptags"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=2")) !== "nill")
43
  exit;
44
  /**/
45
- else if (($level2_ptags = preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_ptags"]))) && is_tag ($level2_ptags) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=2")) !== "nill")
46
  exit;
47
  /**/
48
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_ptags"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=3")) !== "nill")
49
  exit;
50
  /**/
51
- else if (($level3_ptags = preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_ptags"]))) && is_tag ($level3_ptags) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=3")) !== "nill")
52
  exit;
53
  /**/
54
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=4")) !== "nill")
55
  exit;
56
  /**/
57
- else if (($level4_ptags = preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_ptags"]))) && is_tag ($level4_ptags) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=4")) !== "nill")
58
  exit;
59
  }
60
  else if (is_single () && has_tag () && $post_ID)
61
  {
62
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_ptags"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
63
  exit;
64
  /**/
65
- else if (($level1_ptags = preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_ptags"]))) && has_tag ($level1_ptags) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
66
  exit;
67
  /**/
68
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_ptags"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=2")) !== "nill")
69
  exit;
70
  /**/
71
- else if (($level2_ptags = preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_ptags"]))) && has_tag ($level2_ptags) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=2")) !== "nill")
72
  exit;
73
  /**/
74
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_ptags"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=3")) !== "nill")
75
  exit;
76
  /**/
77
- else if (($level3_ptags = preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_ptags"]))) && has_tag ($level3_ptags) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=3")) !== "nill")
78
  exit;
79
  /**/
80
- else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_ptags"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=4")) !== "nill")
81
  exit;
82
  /**/
83
- else if (($level4_ptags = preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_ptags"]))) && has_tag ($level4_ptags) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=4")) !== "nill")
84
  exit;
85
  }
86
  /**/
33
  /**/
34
  if (is_tag () && $tag_ID) /* We also check if this is a post or page with tags, having a restricted tag. */
35
  {
36
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_ptags"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
37
  exit;
38
  /**/
39
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_ptags"] && is_tag (preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_ptags"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
40
  exit;
41
  /**/
42
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_ptags"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (add_query_arg ("s2member_level_req", "2", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
43
  exit;
44
  /**/
45
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_ptags"] && is_tag (preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_ptags"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (add_query_arg ("s2member_level_req", "2", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
46
  exit;
47
  /**/
48
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_ptags"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (add_query_arg ("s2member_level_req", "3", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
49
  exit;
50
  /**/
51
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_ptags"] && is_tag (preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_ptags"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (add_query_arg ("s2member_level_req", "3", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
52
  exit;
53
  /**/
54
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_catgs"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (add_query_arg ("s2member_level_req", "4", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
55
  exit;
56
  /**/
57
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_ptags"] && is_tag (preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_ptags"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (add_query_arg ("s2member_level_req", "4", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
58
  exit;
59
  }
60
  else if (is_single () && has_tag () && $post_ID)
61
  {
62
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_ptags"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
63
  exit;
64
  /**/
65
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_ptags"] && has_tag (preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_ptags"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
66
  exit;
67
  /**/
68
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_ptags"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (add_query_arg ("s2member_level_req", "2", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
69
  exit;
70
  /**/
71
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_ptags"] && has_tag (preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_ptags"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (add_query_arg ("s2member_level_req", "2", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
72
  exit;
73
  /**/
74
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_ptags"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (add_query_arg ("s2member_level_req", "3", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
75
  exit;
76
  /**/
77
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_ptags"] && has_tag (preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_ptags"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (add_query_arg ("s2member_level_req", "3", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
78
  exit;
79
  /**/
80
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_ptags"] === "all" && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (add_query_arg ("s2member_level_req", "4", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
81
  exit;
82
  /**/
83
+ else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_ptags"] && has_tag (preg_split ("/[\r\n\t;,]+/", preg_replace ("/( +)/", "-", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_ptags"]))) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (add_query_arg ("s2member_level_req", "4", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
84
  exit;
85
  }
86
  /**/
includes/functions/register-access.inc.php CHANGED
@@ -33,11 +33,11 @@ function ws_plugin__s2member_check_register_access ($users_can_register = FALSE)
33
  /**/
34
  do_action ("s2member_before_check_register_access");
35
  /**/
36
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["allow_subscribers_in"])
37
  {
38
  return apply_filters ("s2member_check_register_access", ($users_can_register = "1"));
39
  }
40
- else if ($pagenow !== "options-general.php" && ($subscr_id = ws_plugin__s2member_decrypt ($_COOKIE["s2member_subscr_id"])) && ($custom = ws_plugin__s2member_decrypt ($_COOKIE["s2member_custom"])) && preg_match ("/^[1-4](\:|$)/", ($level = ws_plugin__s2member_decrypt ($_COOKIE["s2member_level"]))))
41
  {
42
  global $wpdb; /* Global database object reference. */
43
  /**/
@@ -61,7 +61,7 @@ function ws_plugin__s2member_general_ops_notice ()
61
  /**/
62
  if ($pagenow === "options-general.php" && !isset ($_GET["page"]))
63
  {
64
- $notice = "<em>* Note: The s2Member plugin has control over two options on this page. <code>Anyone Can Register = " . esc_html (get_option ("users_can_register")) . "</code>, and <code>Default Role = " . esc_html (get_option ("default_role")) . "</code>.";
65
  /**/
66
  do_action ("s2member_during_general_ops_notice");
67
  /**/
@@ -182,7 +182,7 @@ function ws_plugin__s2member_register_link_gen ($subscr_id = FALSE, $custom = FA
182
  if ($subscr_id && $custom && $item_number) /* Must have all of these. */
183
  {
184
  $register = ws_plugin__s2member_encrypt ("subscr_id_custom_item_number:.:|:.:" . $subscr_id . ":.:|:.:" . $custom . ":.:|:.:" . $item_number);
185
- $register_link = ws_plugin__s2member_append_query_var (get_bloginfo ("url") . "/", "s2member_register=" . urlencode ($register));
186
  /**/
187
  if ($shrink && ($tinyurl = @file_get_contents ("http://tinyurl.com/api-create.php?url=" . rawurlencode ($register_link))))
188
  return apply_filters ("s2member_register_link_gen", $tinyurl); /* tinyURL is easier to work with. */
@@ -238,13 +238,14 @@ function ws_plugin__s2member_configure_user_registration ($user_id = FALSE)
238
  ws_plugin__s2member_email_config (); /* Configures From: header that will be used in new user notifications. */
239
  /**/
240
  if (!is_admin () /* Only run this particular routine whenever a Member [1-4] is registering themselves with cookies. */
241
- && ($subscr_id = ws_plugin__s2member_decrypt ($_COOKIE["s2member_subscr_id"])) && ($custom = ws_plugin__s2member_decrypt ($_COOKIE["s2member_custom"])) && preg_match ("/^[1-4](\:|$)/", ($level = ws_plugin__s2member_decrypt ($_COOKIE["s2member_level"])))/**/
242
  && (!$usermeta = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = 's2member_subscr_id' AND `meta_value` = '" . $wpdb->escape ($subscr_id) . "' LIMIT 1")))
243
  /* ^ This is for security ^ It checks the database to make sure the User/Member has not already registered in the past, with the same PayPal Subscr. ID. */
244
  {
245
  $processed = "yes"; /* Mark this as yes, to indicate that a routine was successfully processed. */
246
  /**/
247
- list ($level, $ccaps) = preg_split ("/\:/", $level, 2);
 
248
  /**/
249
  $email = $user->user_email;
250
  $login = $user->user_login;
@@ -264,24 +265,37 @@ function ws_plugin__s2member_configure_user_registration ($user_id = FALSE)
264
  /**/
265
  $opt_in = (!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_opt_in"] || $_POST["ws_plugin__s2member_custom_reg_field_opt_in"]) ? true : false;
266
  /**/
267
- $user->set_role ("s2member_level" . $level);
 
 
 
268
  /**/
269
  if ($ccaps) /* Add custom capabilities. */
270
  foreach (preg_split ("/[\r\n\t\s;,]+/", $ccaps) as $ccap)
271
  if (strlen ($ccap)) /* Don't add empty capabilities. */
272
  $user->add_cap ("access_s2member_ccap_" . trim (strtolower ($ccap)));
273
  /**/
274
- update_usermeta ($user_id, "s2member_subscr_id", $subscr_id);
275
- update_usermeta ($user_id, "s2member_custom", $custom);
 
 
 
 
 
 
 
 
 
276
  /**/
277
  do_action ("s2member_during_configure_user_registration_front_side");
278
  }
279
  /**/
280
- else if (!is_admin ()) /* Only run this particular routine whenever a Free Subscriber is registering themselves. */
281
  {
282
  $processed = "yes"; /* Mark this as yes, to indicate that a routine was successfully processed. */
283
  /**/
284
- list ($level, $ccaps) = preg_split ("/\:/", "0:", 2); /* Colon separated level:custom_capability. */
 
285
  /**/
286
  $email = $user->user_email;
287
  $login = $user->user_login;
@@ -304,11 +318,11 @@ function ws_plugin__s2member_configure_user_registration ($user_id = FALSE)
304
  do_action ("s2member_during_configure_user_registration_front_side");
305
  }
306
  /**/
307
- else if (is_admin () && preg_match ("/wp-admin\/user-new\.php/", $_POST["_wp_http_referer"]) && preg_match ("/^(subscriber|s2member_level[1-4])$/", $_POST["role"]))
308
  {
309
  $processed = "yes"; /* Mark this as yes, to indicate that a routine was successfully processed. */
310
  /**/
311
- $level = ($_POST["role"] === "subscriber") ? "0" : preg_replace ("/[^1-4]/", "", $_POST["role"]);
312
  $ccaps = ""; /* Custom Capabilities are not applicable here. */
313
  /**/
314
  $email = $user->user_email;
@@ -393,7 +407,7 @@ if (!function_exists ("wp_generate_password"))
393
  /**/
394
  function ws_plugin__s2member_generate_password ($length = 12, $special_chars = TRUE)
395
  {
396
- do_action ("s2member_before_s2member_generate_password");
397
  /**/
398
  $password = ws_plugin__s2member_random_str_gen ($length, $special_chars);
399
  /**/
33
  /**/
34
  do_action ("s2member_before_check_register_access");
35
  /**/
36
+ if (current_user_can ("create_users") || $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["allow_subscribers_in"])
37
  {
38
  return apply_filters ("s2member_check_register_access", ($users_can_register = "1"));
39
  }
40
+ else if ($pagenow !== "options-general.php" && ($subscr_id = ws_plugin__s2member_decrypt ($_COOKIE["s2member_subscr_id"])) && ($custom = ws_plugin__s2member_decrypt ($_COOKIE["s2member_custom"])) && preg_match ("/^[1-4](\:|$)([a-z_0-9,]+)?(\:)?([0-9] [A-Z])?$/", ($level = ws_plugin__s2member_decrypt ($_COOKIE["s2member_level"]))))
41
  {
42
  global $wpdb; /* Global database object reference. */
43
  /**/
61
  /**/
62
  if ($pagenow === "options-general.php" && !isset ($_GET["page"]))
63
  {
64
+ $notice = "<em>* Note: The s2Member plugin has control over two options on this page. <code>Anyone Can Register = " . esc_html (get_option ("users_can_register")) . "</code>, and <code>Default Role = " . esc_html (get_option ("default_role")) . "</code>. For further details, see: <code>s2Member -> General Options -> Login Welcome Page -> Allow Free Subscribers</code>.";
65
  /**/
66
  do_action ("s2member_during_general_ops_notice");
67
  /**/
182
  if ($subscr_id && $custom && $item_number) /* Must have all of these. */
183
  {
184
  $register = ws_plugin__s2member_encrypt ("subscr_id_custom_item_number:.:|:.:" . $subscr_id . ":.:|:.:" . $custom . ":.:|:.:" . $item_number);
185
+ $register_link = add_query_arg ("s2member_register", $register, get_bloginfo ("url") . "/");
186
  /**/
187
  if ($shrink && ($tinyurl = @file_get_contents ("http://tinyurl.com/api-create.php?url=" . rawurlencode ($register_link))))
188
  return apply_filters ("s2member_register_link_gen", $tinyurl); /* tinyURL is easier to work with. */
238
  ws_plugin__s2member_email_config (); /* Configures From: header that will be used in new user notifications. */
239
  /**/
240
  if (!is_admin () /* Only run this particular routine whenever a Member [1-4] is registering themselves with cookies. */
241
+ && ($subscr_id = ws_plugin__s2member_decrypt ($_COOKIE["s2member_subscr_id"])) && ($custom = ws_plugin__s2member_decrypt ($_COOKIE["s2member_custom"])) && preg_match ("/^[1-4](\:|$)([a-z_0-9,]+)?(\:)?([0-9] [A-Z])?$/", ($level = ws_plugin__s2member_decrypt ($_COOKIE["s2member_level"])))/**/
242
  && (!$usermeta = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = 's2member_subscr_id' AND `meta_value` = '" . $wpdb->escape ($subscr_id) . "' LIMIT 1")))
243
  /* ^ This is for security ^ It checks the database to make sure the User/Member has not already registered in the past, with the same PayPal Subscr. ID. */
244
  {
245
  $processed = "yes"; /* Mark this as yes, to indicate that a routine was successfully processed. */
246
  /**/
247
+ list ($level, $ccaps, $eotper) = preg_split ("/\:/", $level, 3);
248
+ $role = "s2member_level" . $level; /* Level 1-4. */
249
  /**/
250
  $email = $user->user_email;
251
  $login = $user->user_login;
265
  /**/
266
  $opt_in = (!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_opt_in"] || $_POST["ws_plugin__s2member_custom_reg_field_opt_in"]) ? true : false;
267
  /**/
268
+ $user->set_role ($role); /* s2Member Role. */
269
+ /**/
270
+ update_usermeta ($user_id, "s2member_subscr_id", $subscr_id);
271
+ update_usermeta ($user_id, "s2member_custom", $custom);
272
  /**/
273
  if ($ccaps) /* Add custom capabilities. */
274
  foreach (preg_split ("/[\r\n\t\s;,]+/", $ccaps) as $ccap)
275
  if (strlen ($ccap)) /* Don't add empty capabilities. */
276
  $user->add_cap ("access_s2member_ccap_" . trim (strtolower ($ccap)));
277
  /**/
278
+ if ($eotper) /* If a specific EOT Period has been attached; we need to calculate that now. */
279
+ update_usermeta ($user_id, "s2member_auto_eot_time", ws_plugin__s2member_paypal_auto_eot_time (0, 0, 0, $eotper));
280
+ /**/
281
+ if (($transient = md5 ("s2member_transient_ipn_subscr_payment_" . $subscr_id)) && is_array ($subscr_payment = get_transient ($transient)))
282
+ {
283
+ $proxy = array ("s2member_paypal_notify" => "1", "s2member_paypal_proxy" => "s2member_transient_ipn_subscr_payment");
284
+ ws_plugin__s2member_curlpsr (add_query_arg ($proxy, get_bloginfo ("url")), $subscr_payment);
285
+ delete_transient ($transient);
286
+ }
287
+ /**/
288
+ setcookie ("s2member_signup_tracking", ws_plugin__s2member_encrypt ($subscr_id), time () + 31556926, "/");
289
  /**/
290
  do_action ("s2member_during_configure_user_registration_front_side");
291
  }
292
  /**/
293
+ else if (!is_admin () && preg_match ("/^(subscriber|s2member_level[1-4])$/", ($role = $user->roles[0])))
294
  {
295
  $processed = "yes"; /* Mark this as yes, to indicate that a routine was successfully processed. */
296
  /**/
297
+ $level = ($role === "subscriber") ? "0" : preg_replace ("/^s2member_level/", "", $role);
298
+ $ccaps = ""; /* Custom Capabilities are not applicable here. */
299
  /**/
300
  $email = $user->user_email;
301
  $login = $user->user_login;
318
  do_action ("s2member_during_configure_user_registration_front_side");
319
  }
320
  /**/
321
+ else if (is_admin () && preg_match ("/wp-admin\/user-new\.php/", $_POST["_wp_http_referer"]) && preg_match ("/^(subscriber|s2member_level[1-4])$/", ($role = $user->roles[0])))
322
  {
323
  $processed = "yes"; /* Mark this as yes, to indicate that a routine was successfully processed. */
324
  /**/
325
+ $level = ($role === "subscriber") ? "0" : preg_replace ("/^s2member_level/", "", $role);
326
  $ccaps = ""; /* Custom Capabilities are not applicable here. */
327
  /**/
328
  $email = $user->user_email;
407
  /**/
408
  function ws_plugin__s2member_generate_password ($length = 12, $special_chars = TRUE)
409
  {
410
+ do_action ("s2member_before_generate_password");
411
  /**/
412
  $password = ws_plugin__s2member_random_str_gen ($length, $special_chars);
413
  /**/
includes/functions/ruri-level-access.inc.php CHANGED
@@ -27,21 +27,25 @@ function ws_plugin__s2member_check_ruri_level_access ()
27
  {
28
  $current_user = (is_user_logged_in ()) ? wp_get_current_user () : false; /* Is a user logged in? */
29
  /**/
30
- foreach (preg_split ("/[\r\n\t]+/", ws_plugin__s2member_fill_ruri_level_access_rc_vars ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_ruris"], $current_user)) as $str)
31
- if ($str && preg_match ("/" . preg_quote ($str, "/") . "/", $_SERVER["REQUEST_URI"]) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=1")) !== "nill")
32
- exit;
 
33
  /**/
34
- foreach (preg_split ("/[\r\n\t]+/", ws_plugin__s2member_fill_ruri_level_access_rc_vars ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_ruris"], $current_user)) as $str)
35
- if ($str && preg_match ("/" . preg_quote ($str, "/") . "/", $_SERVER["REQUEST_URI"]) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=2")) !== "nill")
36
- exit;
 
37
  /**/
38
- foreach (preg_split ("/[\r\n\t]+/", ws_plugin__s2member_fill_ruri_level_access_rc_vars ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_ruris"], $current_user)) as $str)
39
- if ($str && preg_match ("/" . preg_quote ($str, "/") . "/", $_SERVER["REQUEST_URI"]) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=3")) !== "nill")
40
- exit;
 
41
  /**/
42
- foreach (preg_split ("/[\r\n\t]+/", ws_plugin__s2member_fill_ruri_level_access_rc_vars ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_ruris"], $current_user)) as $str)
43
- if ($str && preg_match ("/" . preg_quote ($str, "/") . "/", $_SERVER["REQUEST_URI"]) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (ws_plugin__s2member_append_query_var (get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]), "s2member_level_req=4")) !== "nill")
44
- exit;
 
45
  /**/
46
  do_action ("s2member_during_check_ruri_level_access");
47
  }
27
  {
28
  $current_user = (is_user_logged_in ()) ? wp_get_current_user () : false; /* Is a user logged in? */
29
  /**/
30
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_ruris"])
31
+ foreach (preg_split ("/[\r\n\t]+/", ws_plugin__s2member_fill_ruri_level_access_rc_vars ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_ruris"], $current_user)) as $str)
32
+ if ($str && preg_match ("/" . preg_quote ($str, "/") . "/", $_SERVER["REQUEST_URI"]) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level1")) && wp_redirect (add_query_arg ("s2member_level_req", "1", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
33
+ exit;
34
  /**/
35
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_ruris"])
36
+ foreach (preg_split ("/[\r\n\t]+/", ws_plugin__s2member_fill_ruri_level_access_rc_vars ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_ruris"], $current_user)) as $str)
37
+ if ($str && preg_match ("/" . preg_quote ($str, "/") . "/", $_SERVER["REQUEST_URI"]) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level2")) && wp_redirect (add_query_arg ("s2member_level_req", "2", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
38
+ exit;
39
  /**/
40
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_ruris"])
41
+ foreach (preg_split ("/[\r\n\t]+/", ws_plugin__s2member_fill_ruri_level_access_rc_vars ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_ruris"], $current_user)) as $str)
42
+ if ($str && preg_match ("/" . preg_quote ($str, "/") . "/", $_SERVER["REQUEST_URI"]) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level3")) && wp_redirect (add_query_arg ("s2member_level_req", "3", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
43
+ exit;
44
  /**/
45
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_ruris"])
46
+ foreach (preg_split ("/[\r\n\t]+/", ws_plugin__s2member_fill_ruri_level_access_rc_vars ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_ruris"], $current_user)) as $str)
47
+ if ($str && preg_match ("/" . preg_quote ($str, "/") . "/", $_SERVER["REQUEST_URI"]) && ws_plugin__s2member_nocache_constants () !== "nill" && (!$current_user || !current_user_can ("access_s2member_level4")) && wp_redirect (add_query_arg ("s2member_level_req", "4", get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]))) !== "nill")
48
+ exit;
49
  /**/
50
  do_action ("s2member_during_check_ruri_level_access");
51
  }
includes/functions/shortcodes.inc.php CHANGED
@@ -16,15 +16,17 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
16
  /*
17
  Function that handles the Shortcode for [s2Member-PayPal-Button /].
18
 
19
- [s2Member-PayPal-Button level="1" ccaps="" desc="" ps="paypal" cc="USD" custom="www.domain.com" tp="0" tt="D" ra="0.01" rp="1" rt="M" rr="1" /]
20
- [s2Member-PayPal-Button page="0" exp="72" desc="Single-Page Access" ps="paypal" cc="USD" custom="www.domain.com" ra="0.01" sp="1" /]
21
 
22
- The desc attribute is only required for Single-Page buttons, optional for others.
23
- The page attribute is only used for Single-Page buttons.
24
 
 
 
 
 
25
  PayPal® Modification Buttons are identified by mb="1".
26
  PayPal® Cancellation Buttons are identified by cb="1".
27
- PayPal® Single-Page Buttons are identified by sp="1".
28
 
29
  Attach to: add_shortcode("s2Member-PayPal-Button");
30
  */
@@ -32,7 +34,16 @@ function ws_plugin__s2member_paypal_button ($attr = FALSE, $content = FALSE, $sh
32
  {
33
  do_action ("s2member_before_paypal_button");
34
  /**/
35
- $sc = shortcode_atts (array ("page" => "0", "exp" => "72", "level" => "1", "ccaps" => "", "desc" => "", "ps" => "paypal", "cc" => "USD", "custom" => $_SERVER["HTTP_HOST"], "tp" => "0", "tt" => "D", "ra" => "0.01", "rp" => "1", "rt" => "M", "rr" => "1", "mb" => "0", "cb" => "0", "sp" => "0"), $attr);
 
 
 
 
 
 
 
 
 
36
  /**/
37
  do_action ("s2member_before_paypal_button_after_shortcode_atts");
38
  /**/
@@ -42,10 +53,12 @@ function ws_plugin__s2member_paypal_button ($attr = FALSE, $content = FALSE, $sh
42
  $code = preg_replace ("/%%endpoint%%/", (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com"), $code);
43
  $code = preg_replace ("/%%paypal_business%%/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"], $code);
44
  /**/
 
 
45
  do_action ("s2member_during_paypal_button_cb");
46
  }
47
  /**/
48
- else if ($sc["sp"]) /* This is a special routine for Single-Page Buttons. Single-Page Buttons use a different template. */
49
  {
50
  $code = trim (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/sp-button.html"));
51
  $code = preg_replace ("/%%endpoint%%/", (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com"), $code);
@@ -56,24 +69,28 @@ function ws_plugin__s2member_paypal_button ($attr = FALSE, $content = FALSE, $sh
56
  $code = preg_replace ("/%%domain%%/", strtolower ($_SERVER["HTTP_HOST"]), $code);
57
  /**/
58
  $code = preg_replace ('/ name\="item_name" value\="(.*?)"/', ' name="item_name" value="' . $sc["desc"] . '"', $code);
59
- $code = preg_replace ('/ name\="item_number" value\="(.*?)"/', ' name="item_number" value="sp:' . $sc["page"] . ':' . $sc["exp"] . '"', $code);
60
  $code = preg_replace ('/ name\="page_style" value\="(.*?)"/', ' name="page_style" value="' . $sc["ps"] . '"', $code);
61
  $code = preg_replace ('/ name\="currency_code" value\="(.*?)"/', ' name="currency_code" value="' . $sc["cc"] . '"', $code);
62
  $code = preg_replace ('/ name\="custom" value\="(.*?)"/', ' name="custom" value="' . $sc["custom"] . '"', $code);
63
  $code = preg_replace ('/ name\="amount" value\="(.*?)"/', ' name="amount" value="' . $sc["ra"] . '"', $code);
64
  /**/
 
 
65
  do_action ("s2member_during_paypal_button_sp");
66
  }
67
  else /* Otherwise, we'll process this Button normally, using the Membership routines. Also handles Modification Buttons. */
68
  {
69
  $sc["desc"] = (!$sc["desc"]) ? $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $sc["level"] . "_label"] : $sc["desc"];
70
- $sc["level_ccaps"] = ($sc["ccaps"]) ? $sc["level"] . ":" . $sc["ccaps"] : $sc["level"];
 
 
71
  /**/
72
  $code = trim (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/button.html"));
73
  $code = preg_replace ("/%%endpoint%%/", (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com"), $code);
74
  $code = preg_replace ("/%%paypal_business%%/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"], $code);
75
  $code = preg_replace ("/%%level_label%%/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $sc["level"] . "_label"], $code);
76
- $code = preg_replace ("/%%cancel_return%%/", get_bloginfo ("url"), $code);
77
  $code = preg_replace ("/%%notify_url%%/", get_bloginfo ("url") . "/?s2member_paypal_notify=1", $code);
78
  $code = preg_replace ("/%%return%%/", get_bloginfo ("url") . "/?s2member_paypal_return=1", $code);
79
  $code = preg_replace ("/%%domain%%/", strtolower ($_SERVER["HTTP_HOST"]), $code);
@@ -81,19 +98,19 @@ function ws_plugin__s2member_paypal_button ($attr = FALSE, $content = FALSE, $sh
81
  /**/
82
  $code = preg_replace ('/ \<\!--(\<input type\="hidden" name\="(amount|src|sra|a1|p1|t1|a3|p3|t3)" value\="(.*?)" \/\>)--\>/', " $1", $code);
83
  $code = ($sc["tp"] <= 0) ? preg_replace ('/ (\<input type\="hidden" name\="(a1|p1|t1)" value\="(.*?)" \/\>)/', " <!--$1-->", $code) : $code;
84
- $code = ($sc["rt"] === "L") ? preg_replace ('/ (\<input type\="hidden" name\="cmd" value\=")(.*?)(" \/\>)/', " $1_xclick$3", $code) : $code;
85
- $code = ($sc["rt"] === "L") ? preg_replace ('/ (\<input type\="hidden" name\="(src|sra|a1|p1|t1|a3|p3|t3)" value\="(.*?)" \/\>)/', " <!--$1-->", $code) : $code;
86
- $code = ($sc["rt"] !== "L") ? preg_replace ('/ (\<input type\="hidden" name\="cmd" value\=")(.*?)(" \/\>)/', " $1_xclick-subscriptions$3", $code) : $code;
87
- $code = ($sc["rt"] !== "L") ? preg_replace ('/ (\<input type\="hidden" name\="amount" value\="(.*?)" \/\>)/', " <!--$1-->", $code) : $code;
88
  /**/
89
  $code = preg_replace ('/ name\="item_name" value\="(.*?)"/', ' name="item_name" value="' . $sc["desc"] . '"', $code);
90
- $code = preg_replace ('/ name\="item_number" value\="(.*?)"/', ' name="item_number" value="' . $sc["level_ccaps"] . '"', $code);
91
  $code = preg_replace ('/ name\="page_style" value\="(.*?)"/', ' name="page_style" value="' . $sc["ps"] . '"', $code);
92
  $code = preg_replace ('/ name\="currency_code" value\="(.*?)"/', ' name="currency_code" value="' . $sc["cc"] . '"', $code);
93
  $code = preg_replace ('/ name\="custom" value\="(.*?)"/', ' name="custom" value="' . $sc["custom"] . '"', $code);
94
  $code = preg_replace ('/ name\="on0" value\="(.*?)"/', ' name="on0" value="' . S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0 . '"', $code);
95
  $code = preg_replace ('/ name\="os0" value\="(.*?)"/', ' name="os0" value="' . S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS0 . '"', $code);
96
- $code = preg_replace ('/ name\="modify" value\="(.*?)"/', ' name="modify" value="' . (($sc["mb"]) ? '1' : '0') . '"', $code);
97
  $code = preg_replace ('/ name\="amount" value\="(.*?)"/', ' name="amount" value="' . $sc["ra"] . '"', $code);
98
  $code = preg_replace ('/ name\="src" value\="(.*?)"/', ' name="src" value="' . $sc["rr"] . '"', $code);
99
  $code = preg_replace ('/ name\="p1" value\="(.*?)"/', ' name="p1" value="' . $sc["tp"] . '"', $code);
@@ -102,6 +119,8 @@ function ws_plugin__s2member_paypal_button ($attr = FALSE, $content = FALSE, $sh
102
  $code = preg_replace ('/ name\="p3" value\="(.*?)"/', ' name="p3" value="' . $sc["rp"] . '"', $code);
103
  $code = preg_replace ('/ name\="t3" value\="(.*?)"/', ' name="t3" value="' . $sc["rt"] . '"', $code);
104
  /**/
 
 
105
  if ($sc["mb"])
106
  do_action ("s2member_during_paypal_button_mb");
107
  else
16
  /*
17
  Function that handles the Shortcode for [s2Member-PayPal-Button /].
18
 
19
+ [s2Member-PayPal-Button level="1" ccaps="" desc="" ps="paypal" cc="USD" custom="www.domain.com" tp="0" tt="D" ra="0.01" rp="1" rt="M" rr="1" image="default" /]
20
+ [s2Member-PayPal-Button page="0" exp="72" desc="Specific Post/Page Access" ps="paypal" cc="USD" custom="www.domain.com" ra="0.01" sp="1" image="default" /]
21
 
22
+ The image attribute will be used as a custom image; when provided; and not equal to "default".
 
23
 
24
+ The desc attribute is only required for Specific Post/Page buttons, optional for others.
25
+ The ids attribute is only used for Specific Post/Page buttons.
26
+
27
+ PayPal® Specific Post/Page Buttons are identified by sp="1".
28
  PayPal® Modification Buttons are identified by mb="1".
29
  PayPal® Cancellation Buttons are identified by cb="1".
 
30
 
31
  Attach to: add_shortcode("s2Member-PayPal-Button");
32
  */
34
  {
35
  do_action ("s2member_before_paypal_button");
36
  /**/
37
+ $attr["tt"] = strtoupper ($attr["tt"]); /* Term lengths absolutely must be provided in upper-case format. */
38
+ $attr["rt"] = strtoupper ($attr["rt"]); /* Term lengths absolutely must be provided in upper-case format. */
39
+ $attr["rr"] = strtoupper ($attr["rr"]); /* Must be provided in upper-case format. Numerical, or BN value. */
40
+ $attr["ccaps"] = strtolower ($attr["ccaps"]); /* Custom Capabilities must be typed in lower-case format. */
41
+ /**/
42
+ $attr["rr"] = ($attr["rt"] === "L") ? "BN" : $attr["rr"]; /* Lifetime Subscriptions absolutely require Buy Now functionality in the (rr) attribute. */
43
+ /**/
44
+ $attr["ids"] = (!$attr["ids"] && $attr["page"]) ? $attr["page"] : $attr["ids"]; /* Backward compatibilty for "page", which was renamed to "ids" in s2Member v3.0. */
45
+ /**/
46
+ $sc = shortcode_atts (array ("ids" => "0", "exp" => "72", "level" => "1", "ccaps" => "", "desc" => "", "ps" => "paypal", "cc" => "USD", "custom" => $_SERVER["HTTP_HOST"], "tp" => "0", "tt" => "D", "ra" => "0.01", "rp" => "1", "rt" => "M", "rr" => "1", "mb" => "0", "cb" => "0", "sp" => "0", "image" => "default"), $attr);
47
  /**/
48
  do_action ("s2member_before_paypal_button_after_shortcode_atts");
49
  /**/
53
  $code = preg_replace ("/%%endpoint%%/", (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com"), $code);
54
  $code = preg_replace ("/%%paypal_business%%/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"], $code);
55
  /**/
56
+ $code = ($sc["image"] && $sc["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . $sc["image"] . '"', $code) : $code;
57
+ /**/
58
  do_action ("s2member_during_paypal_button_cb");
59
  }
60
  /**/
61
+ else if ($sc["sp"]) /* This is a special routine for Specific Post/Page Buttons. Specific Post/Page Buttons use a different template. */
62
  {
63
  $code = trim (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/sp-button.html"));
64
  $code = preg_replace ("/%%endpoint%%/", (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com"), $code);
69
  $code = preg_replace ("/%%domain%%/", strtolower ($_SERVER["HTTP_HOST"]), $code);
70
  /**/
71
  $code = preg_replace ('/ name\="item_name" value\="(.*?)"/', ' name="item_name" value="' . $sc["desc"] . '"', $code);
72
+ $code = preg_replace ('/ name\="item_number" value\="(.*?)"/', ' name="item_number" value="sp:' . $sc["ids"] . ':' . $sc["exp"] . '"', $code);
73
  $code = preg_replace ('/ name\="page_style" value\="(.*?)"/', ' name="page_style" value="' . $sc["ps"] . '"', $code);
74
  $code = preg_replace ('/ name\="currency_code" value\="(.*?)"/', ' name="currency_code" value="' . $sc["cc"] . '"', $code);
75
  $code = preg_replace ('/ name\="custom" value\="(.*?)"/', ' name="custom" value="' . $sc["custom"] . '"', $code);
76
  $code = preg_replace ('/ name\="amount" value\="(.*?)"/', ' name="amount" value="' . $sc["ra"] . '"', $code);
77
  /**/
78
+ $code = ($sc["image"] && $sc["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . $sc["image"] . '"', $code) : $code;
79
+ /**/
80
  do_action ("s2member_during_paypal_button_sp");
81
  }
82
  else /* Otherwise, we'll process this Button normally, using the Membership routines. Also handles Modification Buttons. */
83
  {
84
  $sc["desc"] = (!$sc["desc"]) ? $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $sc["level"] . "_label"] : $sc["desc"];
85
+ /**/
86
+ $sc["level_ccaps_eotper"] = ($sc["rr"] === "BN" && $sc["rt"] !== "L") ? $sc["level"] . ":" . $sc["ccaps"] . ":" . $sc["rp"] . " " . $sc["rt"] : $sc["level"] . ":" . $sc["ccaps"];
87
+ $sc["level_ccaps_eotper"] = rtrim ($sc["level_ccaps_eotper"], ":"); /* Clean any trailing separators from this string. */
88
  /**/
89
  $code = trim (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/button.html"));
90
  $code = preg_replace ("/%%endpoint%%/", (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com"), $code);
91
  $code = preg_replace ("/%%paypal_business%%/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"], $code);
92
  $code = preg_replace ("/%%level_label%%/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $sc["level"] . "_label"], $code);
93
+ $code = preg_replace ("/%%cancel_return%%/", get_bloginfo ("url"), $code); /* This brings them back to Front Page. */
94
  $code = preg_replace ("/%%notify_url%%/", get_bloginfo ("url") . "/?s2member_paypal_notify=1", $code);
95
  $code = preg_replace ("/%%return%%/", get_bloginfo ("url") . "/?s2member_paypal_return=1", $code);
96
  $code = preg_replace ("/%%domain%%/", strtolower ($_SERVER["HTTP_HOST"]), $code);
98
  /**/
99
  $code = preg_replace ('/ \<\!--(\<input type\="hidden" name\="(amount|src|sra|a1|p1|t1|a3|p3|t3)" value\="(.*?)" \/\>)--\>/', " $1", $code);
100
  $code = ($sc["tp"] <= 0) ? preg_replace ('/ (\<input type\="hidden" name\="(a1|p1|t1)" value\="(.*?)" \/\>)/', " <!--$1-->", $code) : $code;
101
+ $code = ($sc["rr"] === "BN") ? preg_replace ('/ (\<input type\="hidden" name\="cmd" value\=")(.*?)(" \/\>)/', " $1_xclick$3", $code) : $code;
102
+ $code = ($sc["rr"] === "BN") ? preg_replace ('/ (\<input type\="hidden" name\="(src|sra|a1|p1|t1|a3|p3|t3)" value\="(.*?)" \/\>)/', " <!--$1-->", $code) : $code;
103
+ $code = ($sc["rr"] !== "BN") ? preg_replace ('/ (\<input type\="hidden" name\="cmd" value\=")(.*?)(" \/\>)/', " $1_xclick-subscriptions$3", $code) : $code;
104
+ $code = ($sc["rr"] !== "BN") ? preg_replace ('/ (\<input type\="hidden" name\="amount" value\="(.*?)" \/\>)/', " <!--$1-->", $code) : $code;
105
  /**/
106
  $code = preg_replace ('/ name\="item_name" value\="(.*?)"/', ' name="item_name" value="' . $sc["desc"] . '"', $code);
107
+ $code = preg_replace ('/ name\="item_number" value\="(.*?)"/', ' name="item_number" value="' . $sc["level_ccaps_eotper"] . '"', $code);
108
  $code = preg_replace ('/ name\="page_style" value\="(.*?)"/', ' name="page_style" value="' . $sc["ps"] . '"', $code);
109
  $code = preg_replace ('/ name\="currency_code" value\="(.*?)"/', ' name="currency_code" value="' . $sc["cc"] . '"', $code);
110
  $code = preg_replace ('/ name\="custom" value\="(.*?)"/', ' name="custom" value="' . $sc["custom"] . '"', $code);
111
  $code = preg_replace ('/ name\="on0" value\="(.*?)"/', ' name="on0" value="' . S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0 . '"', $code);
112
  $code = preg_replace ('/ name\="os0" value\="(.*?)"/', ' name="os0" value="' . S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS0 . '"', $code);
113
+ $code = preg_replace ('/ name\="modify" value\="(.*?)"/', ' name="modify" value="' . (($sc["mb"]) ? "1" : "0") . '"', $code);
114
  $code = preg_replace ('/ name\="amount" value\="(.*?)"/', ' name="amount" value="' . $sc["ra"] . '"', $code);
115
  $code = preg_replace ('/ name\="src" value\="(.*?)"/', ' name="src" value="' . $sc["rr"] . '"', $code);
116
  $code = preg_replace ('/ name\="p1" value\="(.*?)"/', ' name="p1" value="' . $sc["tp"] . '"', $code);
119
  $code = preg_replace ('/ name\="p3" value\="(.*?)"/', ' name="p3" value="' . $sc["rp"] . '"', $code);
120
  $code = preg_replace ('/ name\="t3" value\="(.*?)"/', ' name="t3" value="' . $sc["rt"] . '"', $code);
121
  /**/
122
+ $code = ($sc["image"] && $sc["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . $sc["image"] . '"', $code) : $code;
123
+ /**/
124
  if ($sc["mb"])
125
  do_action ("s2member_during_paypal_button_mb");
126
  else
includes/functions/sp-access.inc.php CHANGED
@@ -14,16 +14,16 @@ Direct access denial.
14
  if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
  exit;
16
  /*
17
- Generates Single-Page Access links.
18
  */
19
- function ws_plugin__s2member_sp_access_link_gen ($page_ID = FALSE, $hours = 72, $shrink = TRUE)
20
  {
21
  do_action ("s2member_before_sp_access_link_gen");
22
  /**/
23
- if ($page_ID && $hours) /* Must have page_ID/hours in order to create an access link. */
24
  {
25
- $sp_access = ws_plugin__s2member_encrypt ("sp_time_hours:.:|:.:" . $page_ID . ":.:|:.:" . strtotime ("now") . ":.:|:.:" . $hours);
26
- $sp_access_link = ws_plugin__s2member_append_query_var (get_page_link ($page_ID), "s2member_sp_access=" . urlencode ($sp_access));
27
  /**/
28
  if ($shrink && ($tinyurl = @file_get_contents ("http://tinyurl.com/api-create.php?url=" . rawurlencode ($sp_access_link))))
29
  return apply_filters ("s2member_sp_access_link_gen", $tinyurl); /* tinyURL is easier to work with. */
@@ -34,7 +34,7 @@ function ws_plugin__s2member_sp_access_link_gen ($page_ID = FALSE, $hours = 72,
34
  return false;
35
  }
36
  /*
37
- Generates Single-Page Access links via ajax tools.
38
  Attach to: add_action("wp_ajax_s2member_sp_access_link");
39
  */
40
  function ws_plugin__s2member_sp_access_link ()
@@ -43,39 +43,76 @@ function ws_plugin__s2member_sp_access_link ()
43
  /**/
44
  if (current_user_can ("edit_plugins")) /* Check priveledges as well. */
45
  if (($nonce = $_POST["s2member_sp_access_link"]) && wp_verify_nonce ($nonce, "ws-plugin--s2member-sp-access-link"))
46
- echo apply_filters ("s2member_sp_access_link", ws_plugin__s2member_sp_access_link_gen ($_POST["s2member_sp_access_link_page"], $_POST["s2member_sp_access_link_hours"]));
47
  /**/
48
  exit;
49
  }
50
  /*
51
- Handles Single-Page Access authentication.
52
  */
53
- function ws_plugin__s2member_sp_access ($page_ID = FALSE)
54
  {
55
  do_action ("s2member_before_sp_access");
56
  /**/
57
  $excluded = apply_filters ("s2member_sp_access_excluded", false);
58
  /**/
59
  if ($excluded || current_user_can ("edit_posts"))
60
- return true; /* Edit access. */
61
  /**/
62
- else if ($_GET["s2member_sp_access"] && $page_ID)
 
 
63
  {
64
- if (is_array ($sp_access = preg_split ("/\:\.\:\|\:\.\:/", ws_plugin__s2member_decrypt ($_GET["s2member_sp_access"]))))
65
  {
66
- if (count ($sp_access) === 4 && $sp_access[0] === "sp_time_hours" && $sp_access[1] == $page_ID && $sp_access[2] >= strtotime ("-" . $sp_access[3] . " hours"))
67
  {
68
- if ($sp_access[2] <= strtotime ("now")) /* Additional sanity check. */
69
- return true; /* Looks good! Single-Page Access granted. */
 
 
 
 
 
 
 
 
 
70
  }
71
  }
72
  /**/
73
- echo '<strong>Your Link Expired:</strong><br />Please contact Support if you need assistance.';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  /**/
75
- exit; /* $_GET["s2member_sp_access"] has expired, or is invalid. */
 
 
76
  }
77
  /**/
78
- else /* No access. */
79
- return false;
80
  }
81
  ?>
14
  if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
  exit;
16
  /*
17
+ Generates Specific Post/Page Access links.
18
  */
19
+ function ws_plugin__s2member_sp_access_link_gen ($sp_IDs = FALSE, $hours = 72, $shrink = TRUE)
20
  {
21
  do_action ("s2member_before_sp_access_link_gen");
22
  /**/
23
+ if (($sp_IDs = preg_replace ("/[^0-9;,]/", "", $sp_IDs)) && ($leading_ID = preg_replace ("/^([0-9]+)(.*?)$/", "$1", $sp_IDs)) && $hours)
24
  {
25
+ $sp_access = ws_plugin__s2member_encrypt ("sp_time_hours:.:|:.:" . $sp_IDs . ":.:|:.:" . strtotime ("now") . ":.:|:.:" . $hours);
26
+ $sp_access_link = add_query_arg ("s2member_sp_access", $sp_access, get_permalink ($leading_ID));
27
  /**/
28
  if ($shrink && ($tinyurl = @file_get_contents ("http://tinyurl.com/api-create.php?url=" . rawurlencode ($sp_access_link))))
29
  return apply_filters ("s2member_sp_access_link_gen", $tinyurl); /* tinyURL is easier to work with. */
34
  return false;
35
  }
36
  /*
37
+ Generates Specific Post/Page Access links via ajax tools.
38
  Attach to: add_action("wp_ajax_s2member_sp_access_link");
39
  */
40
  function ws_plugin__s2member_sp_access_link ()
43
  /**/
44
  if (current_user_can ("edit_plugins")) /* Check priveledges as well. */
45
  if (($nonce = $_POST["s2member_sp_access_link"]) && wp_verify_nonce ($nonce, "ws-plugin--s2member-sp-access-link"))
46
+ echo apply_filters ("s2member_sp_access_link", ws_plugin__s2member_sp_access_link_gen ($_POST["s2member_sp_access_link_ids"], $_POST["s2member_sp_access_link_hours"]));
47
  /**/
48
  exit;
49
  }
50
  /*
51
+ Handles Specific Post/Page Access authentication.
52
  */
53
+ function ws_plugin__s2member_sp_access ($sp_ID = FALSE)
54
  {
55
  do_action ("s2member_before_sp_access");
56
  /**/
57
  $excluded = apply_filters ("s2member_sp_access_excluded", false);
58
  /**/
59
  if ($excluded || current_user_can ("edit_posts"))
60
+ return true; /* Excluded? Or editing? */
61
  /**/
62
+ else if ($sp_ID /* Looking for either a _GET request, or a non-empty session. */
63
+ && (($_GET["s2member_sp_access"] && is_array ($sp_access_values = (array)$_GET["s2member_sp_access"]))/**/
64
+ || (is_array ($sp_access_values = ws_plugin__s2member_sp_access_session ()) && !empty ($sp_access_values))))
65
  {
66
+ foreach ($sp_access_values as $sp_access_value) /* Supports multiple access values in a session. */
67
  {
68
+ if (is_array ($sp_access = preg_split ("/\:\.\:\|\:\.\:/", ws_plugin__s2member_decrypt ($sp_access_value))))
69
  {
70
+ if (count ($sp_access) === 4 && $sp_access[0] === "sp_time_hours" && in_array ($sp_ID, preg_split ("/[\r\n\t\s;,]+/", $sp_access[1])))
71
+ {
72
+ if ($sp_access[2] <= strtotime ("now") && ($sp_access[2] + ($sp_access[3] * 3600)) >= strtotime ("now"))
73
+ {
74
+ if ($_GET["s2member_sp_access"]) /* Store request in a session. */
75
+ ws_plugin__s2member_sp_access_session ($_GET["s2member_sp_access"]);
76
+ /**/
77
+ if (ws_plugin__s2member_ip_restrictions_ok ($_SERVER["REMOTE_ADDR"], $sp_access_value))
78
+ return apply_filters ("s2member_sp_access", true);
79
+ }
80
+ }
81
  }
82
  }
83
  /**/
84
+ if ($_GET["s2member_sp_access"]) /* If this is a Specific Post/Page Link, fail with expiration. */
85
+ {
86
+ echo '<strong>Your Link Expired:</strong><br />Please contact Support if you need assistance.';
87
+ /**/
88
+ exit; /* $_GET["s2member_sp_access"] has expired. Or it is simply invalid. */
89
+ }
90
+ /**/
91
+ return apply_filters ("s2member_sp_access", false);
92
+ }
93
+ /**/
94
+ else /* Access is not possible. */
95
+ return apply_filters ("s2member_sp_access", false);
96
+ }
97
+ /*
98
+ Handles Specific Post/Page sessions, by writing access values into a cookie.
99
+ This function can be used to add a new value into the session, and/or to return the current set of values in the session.
100
+ */
101
+ function ws_plugin__s2member_sp_access_session ($add_sp_access_value = FALSE)
102
+ {
103
+ do_action ("s2member_before_sp_access_session");
104
+ /**/
105
+ $sp_access_values = ($_COOKIE["s2member_sp_access"]) ? preg_split ("/\:\.\:\|\:\.\:/", $_COOKIE["s2member_sp_access"]) : array ();
106
+ /**/
107
+ if ($add_sp_access_value && !in_array ($add_sp_access_value, $sp_access_values)) /* If it's not in the session already. */
108
+ {
109
+ $sp_access_values[] = $add_sp_access_value; /* Add an access value, and update the delimited session cookie. */
110
  /**/
111
+ $cookie = implode (":.:|:.:", $sp_access_values); /* Implode the access values into a delimited string. */
112
+ $cookie = (strlen ($cookie) >= 4096) ? $add_sp_access_value : $cookie; /* Max cookie size is 4kbs. */
113
+ setcookie ("s2member_sp_access", $cookie, time () + 31556926, "/");
114
  }
115
  /**/
116
+ return apply_filters ("s2member_sp_access_session", $sp_access_values);
 
117
  }
118
  ?>
includes/functions/tracking-codes.inc.php ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright: © 2009 WebSharks, Inc. ( coded in the USA )
4
+ <mailto:support@websharks-inc.com> <http://www.websharks-inc.com/>
5
+
6
+ Released under the terms of the GNU General Public License.
7
+ You should have received a copy of the GNU General Public License,
8
+ along with this software. In the main directory, see: /licensing/
9
+ If not, see: <http://www.gnu.org/licenses/>.
10
+ */
11
+ /*
12
+ Direct access denial.
13
+ */
14
+ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
+ exit;
16
+ /*
17
+ Function that displays Signup Tracking Codes.
18
+ These are stored inside s2Member's Transient Queue by the IPN processor.
19
+
20
+ Attach to: add_action("login_form_register");
21
+ Attach to: add_action("login_form_login");
22
+ Attach to: add_action("wp_footer");
23
+
24
+ Tracking Codes are only displayed/processed one time.
25
+ s2Member will display Tracking Codes in (1) of these 3 locations:
26
+ 1. If possible, on the Registration Form, after returning from PayPal®.
27
+ 2. Otherwise, if possible, on the Login Form after Registration is completed.
28
+ 3. Otherwise, in the footer of your theme, after both Registration and Login.
29
+ */
30
+ function ws_plugin__s2member_display_signup_tracking_codes ()
31
+ {
32
+ do_action ("s2member_before_display_signup_tracking_codes");
33
+ /**/
34
+ if (($subscr_id = ws_plugin__s2member_decrypt ($_COOKIE["s2member_subscr_id"])) || ($subscr_id = ws_plugin__s2member_decrypt ($_COOKIE["s2member_signup_tracking"])))
35
+ {
36
+ if (($code = get_transient ($transient = md5 ("s2member_transient_signup_tracking_codes_" . $subscr_id))))
37
+ {
38
+ delete_transient ($transient); /* Only display this ONE time. Remove transient immediately. */
39
+ /**/
40
+ echo '<img src="' . add_query_arg ("s2member_delete_signup_tracking_cookie", "1", get_bloginfo ("url")) . '" alt="." style="width:1px; height:1px; border:0;" />' . "\n";
41
+ /**/
42
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["is_wpmu_farm"])
43
+ {
44
+ echo $code . "\n"; /* No PHP allowed here. */
45
+ }
46
+ else /* Otherwise, it's safe to allow PHP code. */
47
+ {
48
+ eval ("?>" . $code);
49
+ }
50
+ /**/
51
+ do_action ("s2member_during_display_signup_tracking_codes");
52
+ }
53
+ }
54
+ /**/
55
+ do_action ("s2member_after_display_signup_tracking_codes");
56
+ }
57
+ /*
58
+ Removes s2Member's temporary tracking cookie.
59
+ Attach to: add_action("init");
60
+ */
61
+ function ws_plugin__s2member_delete_signup_tracking_cookie ()
62
+ {
63
+ do_action ("s2member_before_delete_signup_tracking_cookie");
64
+ /**/
65
+ if ($_GET["s2member_delete_signup_tracking_cookie"]) /* Removes cookie. */
66
+ {
67
+ setcookie ("s2member_signup_tracking", "", time () + 31556926, "/");
68
+ /**/
69
+ do_action ("s2member_during_delete_signup_tracking_cookie");
70
+ /**/
71
+ exit;
72
+ }
73
+ /**/
74
+ do_action ("s2member_after_delete_signup_tracking_cookie");
75
+ }
76
+ /*
77
+ Function that displays Specific Post/Page Tracking Codes.
78
+ These are stored inside s2Member's Transient Queue,
79
+ by BOTH the IPN & Return-Data processors.
80
+
81
+ Attach to: add_action("wp_footer");
82
+
83
+ Specific Post/Page Tracking Codes are only displayed/processed one time.
84
+ s2Member will display Tracking Codes in the footer of your theme.
85
+ */
86
+ function ws_plugin__s2member_display_sp_tracking_codes ()
87
+ {
88
+ do_action ("s2member_before_display_sp_tracking_codes");
89
+ /**/
90
+ if (($txn_id = ws_plugin__s2member_decrypt ($_COOKIE["s2member_sp_tracking"])))
91
+ {
92
+ if (($code = get_transient ($transient = md5 ("s2member_transient_sp_tracking_codes_" . $txn_id))))
93
+ {
94
+ delete_transient ($transient); /* Only display this ONE time. Remove transient immediately. */
95
+ /**/
96
+ echo '<img src="' . add_query_arg ("s2member_delete_sp_tracking_cookie", "1", get_bloginfo ("url")) . '" alt="." style="width:1px; height:1px; border:0;" />' . "\n";
97
+ /**/
98
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["is_wpmu_farm"])
99
+ {
100
+ echo $code . "\n"; /* No PHP allowed here. */
101
+ }
102
+ else /* Otherwise, it's safe to allow PHP code. */
103
+ {
104
+ eval ("?>" . $code);
105
+ }
106
+ /**/
107
+ do_action ("s2member_during_display_sp_tracking_codes");
108
+ }
109
+ }
110
+ /**/
111
+ do_action ("s2member_after_display_sp_tracking_codes");
112
+ }
113
+ /*
114
+ Removes s2Member's temporary tracking cookie.
115
+ Attach to: add_action("init");
116
+ */
117
+ function ws_plugin__s2member_delete_sp_tracking_cookie ()
118
+ {
119
+ do_action ("s2member_before_delete_sp_tracking_cookie");
120
+ /**/
121
+ if ($_GET["s2member_delete_sp_tracking_cookie"]) /* Removes cookie. */
122
+ {
123
+ setcookie ("s2member_sp_tracking", "", time () + 31556926, "/");
124
+ /**/
125
+ do_action ("s2member_during_delete_sp_tracking_cookie");
126
+ /**/
127
+ exit;
128
+ }
129
+ /**/
130
+ do_action ("s2member_after_delete_sp_tracking_cookie");
131
+ }
132
+ ?>
includes/functions/user-deletions.inc.php CHANGED
@@ -21,20 +21,23 @@ function ws_plugin__s2member_handle_user_deletions ($user_id = FALSE)
21
  {
22
  do_action ("s2member_before_handle_user_deletions");
23
  /**/
24
- $user = new WP_User ($user_id);
25
- $paypal["custom"] = get_usermeta ($user_id, "s2member_custom");
26
- $paypal["subscr_id"] = get_usermeta ($user_id, "s2member_subscr_id");
27
  /**/
28
- if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_del_notification_urls"] && is_object ($user) && $paypal["subscr_id"] && $paypal["custom"] && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
 
 
 
29
  {
30
  foreach (preg_split ("/[\r\n\t]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_del_notification_urls"]) as $url) /* Handle eot notifications on user deletion. */
31
- if (($url = preg_replace ("/%%cv([0-9]+)%%/ei", 'urlencode(trim($cv[$1]))', $url)) && ($url = preg_replace ("/%%subscr_id%%/i", urlencode ($paypal["subscr_id"]), $url)))
32
  if (($url = preg_replace ("/%%user_first_name%%/i", urlencode ($user->first_name), $url)) && ($url = preg_replace ("/%%user_last_name%%/i", urlencode ($user->last_name), $url)))
33
  if (($url = preg_replace ("/%%user_full_name%%/i", urlencode (trim ($user->first_name . " " . $user->last_name)), $url)))
34
  if (($url = preg_replace ("/%%user_email%%/i", urlencode ($user->user_email), $url)))
35
  /**/
36
  if (($url = trim ($url))) /* Make sure it is not empty. */
37
  ws_plugin__s2member_curlpsr ($url, "s2member=1");
 
 
38
  }
39
  /**/
40
  do_action ("s2member_after_handle_user_deletions");
21
  {
22
  do_action ("s2member_before_handle_user_deletions");
23
  /**/
24
+ $user = new WP_User ($user_id); /* Acquire user obj. */
 
 
25
  /**/
26
+ $custom = get_usermeta ($user_id, "s2member_custom");
27
+ $subscr_id = get_usermeta ($user_id, "s2member_subscr_id");
28
+ /**/
29
+ if (is_object ($user) && $subscr_id && $custom && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_del_notification_urls"] && is_array ($cv = preg_split ("/\|/", $custom)))
30
  {
31
  foreach (preg_split ("/[\r\n\t]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_del_notification_urls"]) as $url) /* Handle eot notifications on user deletion. */
32
+ if (($url = preg_replace ("/%%cv([0-9]+)%%/ei", 'urlencode(trim($cv[$1]))', $url)) && ($url = preg_replace ("/%%subscr_id%%/i", urlencode ($subscr_id), $url)))
33
  if (($url = preg_replace ("/%%user_first_name%%/i", urlencode ($user->first_name), $url)) && ($url = preg_replace ("/%%user_last_name%%/i", urlencode ($user->last_name), $url)))
34
  if (($url = preg_replace ("/%%user_full_name%%/i", urlencode (trim ($user->first_name . " " . $user->last_name)), $url)))
35
  if (($url = preg_replace ("/%%user_email%%/i", urlencode ($user->user_email), $url)))
36
  /**/
37
  if (($url = trim ($url))) /* Make sure it is not empty. */
38
  ws_plugin__s2member_curlpsr ($url, "s2member=1");
39
+ /**/
40
+ do_action ("s2member_during_handle_user_deletions");
41
  }
42
  /**/
43
  do_action ("s2member_after_handle_user_deletions");
includes/functions/user-has-wp-role.inc.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright: © 2009 WebSharks, Inc. ( coded in the USA )
4
+ <mailto:support@websharks-inc.com> <http://www.websharks-inc.com/>
5
+
6
+ Released under the terms of the GNU General Public License.
7
+ You should have received a copy of the GNU General Public License,
8
+ along with this software. In the main directory, see: /licensing/
9
+ If not, see: <http://www.gnu.org/licenses/>.
10
+ */
11
+ /*
12
+ Direct access denial.
13
+ */
14
+ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
+ exit;
16
+ /*
17
+ Function for determing whether $user has a built-in WP Role.
18
+ One of: (administrator|editor|author|contributor).
19
+ By default, this excludes the "subscriber" role.
20
+ */
21
+ function ws_plugin__s2member_user_has_wp_role ($user = FALSE, $exclude = array ("subscriber"))
22
+ {
23
+ do_action ("s2member_before_user_has_wp_role");
24
+ /**/
25
+ if (!is_object ($user) || !is_array ($user->roles) || empty ($user->roles))
26
+ return apply_filters ("s2member_user_has_wp_role", false);
27
+ /**/
28
+ $exclude = (array)$exclude; /* Force array on the exclusions. */
29
+ /**/
30
+ if (in_array ("administrator", $exclude) || !in_array ("administrator", $user->roles))
31
+ if (in_array ("editor", $exclude) || !in_array ("editor", $user->roles))
32
+ if (in_array ("author", $exclude) || !in_array ("author", $user->roles))
33
+ if (in_array ("contributor", $exclude) || !in_array ("contributor", $user->roles))
34
+ if (in_array ("subscriber", $exclude) || !in_array ("subscriber", $user->roles))
35
+ return apply_filters ("s2member_user_has_wp_role", false);
36
+ /**/
37
+ return apply_filters ("s2member_user_has_wp_role", true);
38
+ }
39
+ ?>
includes/functions/user-notes.inc.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright: © 2009 WebSharks, Inc. ( coded in the USA )
4
+ <mailto:support@websharks-inc.com> <http://www.websharks-inc.com/>
5
+
6
+ Released under the terms of the GNU General Public License.
7
+ You should have received a copy of the GNU General Public License,
8
+ along with this software. In the main directory, see: /licensing/
9
+ If not, see: <http://www.gnu.org/licenses/>.
10
+ */
11
+ /*
12
+ Direct access denial.
13
+ */
14
+ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
15
+ exit;
16
+ /*
17
+ Append a note onto a specific User/Member's account.
18
+ */
19
+ function ws_plugin__s2member_append_user_notes ($user_id = FALSE, $notes = FALSE)
20
+ {
21
+ do_action ("s2member_before_append_user_notes");
22
+ /**/
23
+ if ($user_id && $notes && is_string ($notes)) /* Must have these. */
24
+ {
25
+ $notes = trim (get_usermeta ($user_id, "s2member_notes") . "\n" . $notes);
26
+ $notes = apply_filters ("s2member_append_user_notes", $notes);
27
+ update_usermeta ($user_id, "s2member_notes", $notes);
28
+ }
29
+ /**/
30
+ return $notes; /* Return full set of notes. */
31
+ }
32
+ /*
33
+ Clear specific notes from a User/Member's account; based on line-by-line regex.
34
+ */
35
+ function ws_plugin__s2member_clear_user_note_lines ($user_id = FALSE, $regex = FALSE)
36
+ {
37
+ do_action ("s2member_before_clear_user_note_lines");
38
+ /**/
39
+ if ($user_id && $regex && is_string ($regex) && ($lines = array ()))
40
+ {
41
+ /* Careful here to preserve empty lines. */
42
+ $notes = trim (get_usermeta ($user_id, "s2member_notes"));
43
+ foreach (preg_split ("/\n/", $notes) as $line)
44
+ if (!preg_match ($regex, $line))
45
+ $lines[] = $line;
46
+ /**/
47
+ $notes = apply_filters ("s2member_clear_user_note_lines", trim (implode ("\n", $lines)));
48
+ update_usermeta ($user_id, "s2member_notes", $notes);
49
+ }
50
+ /**/
51
+ return $notes; /* Return full set of notes. */
52
+ }
53
+ ?>
includes/functions/users-list.inc.php CHANGED
@@ -93,10 +93,13 @@ function ws_plugin__s2member_users_list_edit_cols ($user = FALSE)
93
  /**/
94
  echo '<table class="form-table">' . "\n";
95
  /**/
96
- echo '<tr>' . "\n";
97
- echo '<th><label>PayPal® Subscr. ID</label> <a href="#" onclick="alert(\'This will be filled automatically by s2Member, as needed.\\n\\nA PayPal® Subscr ID is only valid for paid Members. This field will always be empty for Free Subscribers, Administrators, Contributors, and Authors. This field is only editable for Customer Service purposes; just in case you ever need to update the PayPal® Subscr ID manually. You are not likely to need this, but s2Member makes it editable, just in case.\'); return false;">[?]</a></th>' . "\n";
98
- echo '<td><input type="text" name="ws_plugin__s2member_profile_s2member_subscr_id" value="' . esc_attr (get_usermeta ($user->ID, "s2member_subscr_id")) . '" class="regular-text" /></td>' . "\n";
99
- echo '</tr>' . "\n";
 
 
 
100
  /**/
101
  foreach ($user->allcaps as $cap => $cap_enabled)
102
  if (preg_match ("/^access_s2member_ccap_/", $cap))
@@ -104,26 +107,56 @@ function ws_plugin__s2member_users_list_edit_cols ($user = FALSE)
104
  /**/
105
  echo '<tr>' . "\n";
106
  echo '<th><label>Custom Capabilities</label> <a href="#" onclick="alert(\'Optional. This is VERY advanced. For full details, see:\\ns2Member -> API Scripting -> Custom Capabilities.\'); return false;">[?]</a></th>' . "\n";
107
- echo '<td><input type="text" name="ws_plugin__s2member_profile_s2member_ccaps" value="' . esc_attr (((!empty ($ccaps)) ? implode (",", $ccaps) : "")) . '" class="regular-text" onkeyup="this.value = jQuery.trim (jQuery.trim (this.value).replace (/[ \-]/g, \'_\').replace (/[^A-Z_0-9,]/gi, \'\').toLowerCase ());"; /></td>' . "\n";
108
  echo '</tr>' . "\n";
109
  /**/
 
 
 
 
 
 
 
 
 
 
110
  if (!defined ("BP_VERSION")) /* Custom fields are not compatible when running together with BuddyPress. */
111
  {
112
- $fields = get_usermeta ($user->ID, "s2member_custom_fields");
113
- /**/
114
- foreach (preg_split ("/[\r\n\t;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_fields"]) as $field)
115
  {
116
- if ($field = trim ($field, "* \t\n\r\0\x0B")) /* Don't process empty fields. */
 
 
 
 
 
 
 
 
117
  {
118
- echo '<tr>' . "\n";
119
- echo '<th><label>' . esc_html ($field) . ' </label></th>' . "\n";
120
- $field = preg_replace ("/[^a-z0-9]/i", "_", strtolower ($field));
121
- echo '<td><input type="text" name="ws_plugin__s2member_profile_' . esc_attr ($field) . '" value="' . esc_attr ($fields[$field]) . '" class="regular-text" /></td>' . "\n";
122
- echo '</tr>' . "\n";
 
 
 
123
  }
 
 
 
 
 
 
124
  }
125
  }
126
  /**/
 
 
 
 
 
127
  do_action ("s2member_during_users_list_edit_cols");
128
  /**/
129
  echo '</table>' . "\n";
@@ -149,6 +182,7 @@ function ws_plugin__s2member_users_list_update_cols ($user_id = FALSE)
149
  if (is_array ($_POST = stripslashes_deep ($_POST)) && !empty ($_POST))
150
  {
151
  $user = new WP_User ($user_id);
 
152
  update_usermeta ($user_id, "s2member_subscr_id", $_POST["ws_plugin__s2member_profile_s2member_subscr_id"]);
153
  /**/
154
  foreach ($user->allcaps as $cap => $cap_enabled)
@@ -159,6 +193,9 @@ function ws_plugin__s2member_users_list_update_cols ($user_id = FALSE)
159
  if (strlen ($ccap)) /* Don't add empty capabilities. */
160
  $user->add_cap ("access_s2member_ccap_" . trim (strtolower ($ccap)));
161
  /**/
 
 
 
162
  if (!defined ("BP_VERSION")) /* Custom fields are not compatible when running together with BuddyPress. */
163
  {
164
  foreach (preg_split ("/[\r\n\t;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_fields"]) as $field)
@@ -173,6 +210,8 @@ function ws_plugin__s2member_users_list_update_cols ($user_id = FALSE)
173
  update_usermeta ($user_id, "s2member_custom_fields", $fields);
174
  }
175
  /**/
 
 
176
  do_action ("s2member_during_users_list_update_cols");
177
  }
178
  }
93
  /**/
94
  echo '<table class="form-table">' . "\n";
95
  /**/
96
+ if (!ws_plugin__s2member_user_has_wp_role ($user)) /* Not for WP Roles. */
97
+ {
98
+ echo '<tr>' . "\n";
99
+ echo '<th><label>PayPal® Subscr. ID</label> <a href="#" onclick="alert(\'This will be filled automatically by s2Member.\\n\\nA PayPal® Subscr ID is only valid for paid Members. This field will always be empty for Free Subscribers, Administrators, Contributors, and Authors. This field is only editable for Customer Service purposes; just in case you ever need to update the PayPal® Subscr ID manually. You are not likely to need this, but s2Member makes it editable, just in case.\'); return false;">[?]</a></th>' . "\n";
100
+ echo '<td><input type="text" name="ws_plugin__s2member_profile_s2member_subscr_id" value="' . format_to_edit (get_usermeta ($user->ID, "s2member_subscr_id")) . '" class="regular-text" /></td>' . "\n";
101
+ echo '</tr>' . "\n";
102
+ }
103
  /**/
104
  foreach ($user->allcaps as $cap => $cap_enabled)
105
  if (preg_match ("/^access_s2member_ccap_/", $cap))
107
  /**/
108
  echo '<tr>' . "\n";
109
  echo '<th><label>Custom Capabilities</label> <a href="#" onclick="alert(\'Optional. This is VERY advanced. For full details, see:\\ns2Member -> API Scripting -> Custom Capabilities.\'); return false;">[?]</a></th>' . "\n";
110
+ echo '<td><input type="text" name="ws_plugin__s2member_profile_s2member_ccaps" value="' . format_to_edit (((!empty ($ccaps)) ? implode (",", $ccaps) : "")) . '" class="regular-text" onkeyup="this.value = jQuery.trim (jQuery.trim (this.value).replace (/[ \-]/g, \'_\').replace (/[^A-Z_0-9,]/gi, \'\').toLowerCase ());"; /></td>' . "\n";
111
  echo '</tr>' . "\n";
112
  /**/
113
+ if (!ws_plugin__s2member_user_has_wp_role ($user)) /* Not for WP Roles. */
114
+ {
115
+ echo '<tr>' . "\n";
116
+ $auto_eot_time = get_usermeta ($user->ID, "s2member_auto_eot_time");
117
+ $auto_eot_time = ($auto_eot_time) ? date ("D M j, Y g:i a T", $auto_eot_time) : "";
118
+ echo '<th><label>Automatic EOT Time:</label> <a href="#" onclick="alert(\'EOT = End Of Term. ( i.e. Account Expiration / Termination. ).\\n\\nIf you leave this empty, s2Member will configure an EOT Time automatically, based on the PayPal® Subscription associated with this account. In other words, if a PayPal® Subscription expires, is cancelled, terminated, refunded, reversed, or charged back to you; s2Member will deal with the EOT automatically.\\n\\nThat being said, if you would rather take control over this, you can. If you type in a date manually, s2Member will obey the Auto-EOT Time that you\\\'ve given, no matter what. In other words, you can force certain Members to expire automatically, at a time that you specify. s2Member will obey.\\n\\nValid formats for Automatic EOT Time:\\n\\nmm/dd/yyyy\\nyyyy-mm-dd\\n+1 year\\n+2 weeks\\n+2 months\\n+10 minutes\\nnext thursday\\ntomorrow\\ntoday\\n\\n* anything compatible with PHP\\\'s strtotime() function.\'); return false;">[?]</a>' . (($auto_eot_time) ? '<br /><small>( based on server time )</small>' : '') . '</th>' . "\n";
119
+ echo '<td><input type="text" name="ws_plugin__s2member_profile_s2member_auto_eot_time" value="' . format_to_edit ($auto_eot_time) . '" class="regular-text" /></td>' . "\n";
120
+ echo '</tr>' . "\n";
121
+ }
122
+ /**/
123
  if (!defined ("BP_VERSION")) /* Custom fields are not compatible when running together with BuddyPress. */
124
  {
125
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_fields"]) /* Only if configured. */
 
 
126
  {
127
+ echo '<tr>' . "\n";
128
+ echo '<td colspan="2">' . "\n";
129
+ echo '<div style="height:1px; line-height:1px; background:#CCCCCC;"></div>' . "\n";
130
+ echo '</td>' . "\n";
131
+ echo '</tr>' . "\n";
132
+ /**/
133
+ $fields = get_usermeta ($user->ID, "s2member_custom_fields"); /* Get existing field values. */
134
+ /**/
135
+ foreach (preg_split ("/[\r\n\t;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_fields"]) as $field)
136
  {
137
+ if ($field = trim ($field, "* \t\n\r\0\x0B")) /* Don't process empty fields. */
138
+ {
139
+ echo '<tr>' . "\n";
140
+ echo '<th><label>' . esc_html ($field) . ' </label></th>' . "\n";
141
+ $field = preg_replace ("/[^a-z0-9]/i", "_", strtolower ($field));
142
+ echo '<td><input type="text" name="ws_plugin__s2member_profile_' . esc_attr ($field) . '" value="' . format_to_edit ($fields[$field]) . '" class="regular-text" /></td>' . "\n";
143
+ echo '</tr>' . "\n";
144
+ }
145
  }
146
+ /**/
147
+ echo '<tr>' . "\n";
148
+ echo '<td colspan="2">' . "\n";
149
+ echo '<div style="height:1px; line-height:1px; background:#CCCCCC;"></div>' . "\n";
150
+ echo '</td>' . "\n";
151
+ echo '</tr>' . "\n";
152
  }
153
  }
154
  /**/
155
+ echo '<tr>' . "\n";
156
+ echo '<th><label>Administrative<br />Notations:</label> <a href="#" onclick="alert(\'This is for Administrative purposes. You can keep a list of Notations about this account. These Notations are private; Users/Members will never see these.\\n\\n*Note* The s2Member software may `append` Notes to this field occassionaly, under special circumstances. For example, when/if s2Member demotes a paid Member to a Free Subscriber, s2Member will leave a Note in this field.\'); return false;">[?]</a></th>' . "\n";
157
+ echo '<td><textarea name="ws_plugin__s2member_profile_s2member_notes" rows="5" wrap="off" spellcheck="false">' . format_to_edit (get_usermeta ($user->ID, "s2member_notes")) . '</textarea></td>' . "\n";
158
+ echo '</tr>' . "\n";
159
+ /**/
160
  do_action ("s2member_during_users_list_edit_cols");
161
  /**/
162
  echo '</table>' . "\n";
182
  if (is_array ($_POST = stripslashes_deep ($_POST)) && !empty ($_POST))
183
  {
184
  $user = new WP_User ($user_id);
185
+ /**/
186
  update_usermeta ($user_id, "s2member_subscr_id", $_POST["ws_plugin__s2member_profile_s2member_subscr_id"]);
187
  /**/
188
  foreach ($user->allcaps as $cap => $cap_enabled)
193
  if (strlen ($ccap)) /* Don't add empty capabilities. */
194
  $user->add_cap ("access_s2member_ccap_" . trim (strtolower ($ccap)));
195
  /**/
196
+ $auto_eot_time = ($eot = $_POST["ws_plugin__s2member_profile_s2member_auto_eot_time"]) ? strtotime ($eot) : "";
197
+ update_usermeta ($user_id, "s2member_auto_eot_time", $auto_eot_time);
198
+ /**/
199
  if (!defined ("BP_VERSION")) /* Custom fields are not compatible when running together with BuddyPress. */
200
  {
201
  foreach (preg_split ("/[\r\n\t;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_fields"]) as $field)
210
  update_usermeta ($user_id, "s2member_custom_fields", $fields);
211
  }
212
  /**/
213
+ update_usermeta ($user_id, "s2member_notes", $_POST["ws_plugin__s2member_profile_s2member_notes"]);
214
+ /**/
215
  do_action ("s2member_during_users_list_update_cols");
216
  }
217
  }
includes/functions/utilities.inc.php CHANGED
@@ -99,16 +99,6 @@ function ws_plugin__s2member_get ($function = FALSE)
99
  return;
100
  }
101
  /*
102
- Function for appending query string vars onto the end.
103
- */
104
- function ws_plugin__s2member_append_query_var ($url = FALSE, $var = FALSE)
105
- {
106
- if (is_string ($url) && $url && is_string ($var) && $var)
107
- return preg_match ("/\?/", $url) ? $url . "&" . $var : $url . "?" . $var;
108
- /**/
109
- return $url;
110
- }
111
- /*
112
  Function checks if a post is in a child category.
113
  */
114
  function ws_plugin__s2member_in_descendant_category ($cats = FALSE, $post_ID = FALSE)
@@ -305,4 +295,65 @@ function ws_plugin__s2member_random_str_gen ($length = 12, $special_chars = TRUE
305
  /**/
306
  return $random_str;
307
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  ?>
99
  return;
100
  }
101
  /*
 
 
 
 
 
 
 
 
 
 
102
  Function checks if a post is in a child category.
103
  */
104
  function ws_plugin__s2member_in_descendant_category ($cats = FALSE, $post_ID = FALSE)
295
  /**/
296
  return $random_str;
297
  }
298
+ /*
299
+ Function that determines the difference between two timestamps. Returns the difference in a human readable format.
300
+ Supports: minutes, hours, days, weeks, months, and years. This is an improvement on WordPress® human_time_diff().
301
+ This returns an "approximate" time difference. Rounded to the nearest minute, hour, day, week, month, year.
302
+ */
303
+ function ws_plugin__s2member_approx_time_difference ($from = FALSE, $to = FALSE)
304
+ {
305
+ $from = (!$from) ? strtotime ("now") : (int)$from;
306
+ $to = (!$to) ? strtotime ("now") : (int)$to;
307
+ /**/
308
+ if (($difference = abs ($to - $from)) < 3600)
309
+ {
310
+ $m = (int)round ($difference / 60);
311
+ /**/
312
+ $since = ($m < 1) ? "less than a minute" : $since;
313
+ $since = ($m === 1) ? "1 minute" : $since;
314
+ $since = ($m > 1) ? $m . " minutes" : $since;
315
+ $since = ($m >= 60) ? "about 1 hour" : $since;
316
+ }
317
+ else if ($difference >= 3600 && $difference < 86400)
318
+ {
319
+ $h = (int)round ($difference / 3600);
320
+ /**/
321
+ $since = ($h === 1) ? "1 hour" : $since;
322
+ $since = ($h > 1) ? $h . " hours" : $since;
323
+ $since = ($h >= 24) ? "about 1 day" : $since;
324
+ }
325
+ else if ($difference >= 86400 && $difference < 604800)
326
+ {
327
+ $d = (int)round ($difference / 86400);
328
+ /**/
329
+ $since = ($d === 1) ? "1 day" : $since;
330
+ $since = ($d > 1) ? $d . " days" : $since;
331
+ $since = ($d >= 7) ? "about 1 week" : $since;
332
+ }
333
+ else if ($difference >= 604800 && $difference < 2592000)
334
+ {
335
+ $w = (int)round ($difference / 604800);
336
+ /**/
337
+ $since = ($w === 1) ? "1 week" : $since;
338
+ $since = ($w > 1) ? $w . " weeks" : $since;
339
+ $since = ($w >= 4) ? "about 1 month" : $since;
340
+ }
341
+ else if ($difference >= 2592000 && $difference < 31556926)
342
+ {
343
+ $m = (int)round ($difference / 2592000);
344
+ /**/
345
+ $since = ($m === 1) ? "1 month" : $since;
346
+ $since = ($m > 1) ? $m . " months" : $since;
347
+ $since = ($m >= 12) ? "about 1 year" : $since;
348
+ }
349
+ else if ($difference >= 31556926) /* Years. */
350
+ {
351
+ $y = (int)round ($difference / 31556926);
352
+ /**/
353
+ $since = ($y === 1) ? "1 year" : $since;
354
+ $since = ($y > 1) ? $y . " years" : $since;
355
+ }
356
+ /**/
357
+ return $since;
358
+ }
359
  ?>
includes/hooks.inc.php CHANGED
@@ -26,6 +26,8 @@ add_action ("init", "ws_plugin__s2member_paypal_return");
26
  add_action ("init", "ws_plugin__s2member_paypal_notify");
27
  add_action ("init", "ws_plugin__s2member_check_file_download_access");
28
  add_action ("init", "ws_plugin__s2member_handle_profile_modifications");
 
 
29
  /**/
30
  add_action ("template_redirect", "ws_plugin__s2member_check_ruri_level_access", 1);
31
  add_action ("template_redirect", "ws_plugin__s2member_check_catg_level_access", 1);
@@ -48,6 +50,10 @@ add_action ("wp_login", "ws_plugin__s2member_login_redirect");
48
  add_action ("login_head", "ws_plugin__s2member_login_header_styles");
49
  add_filter ("login_headerurl", "ws_plugin__s2member_login_header_url");
50
  add_filter ("login_headertitle", "ws_plugin__s2member_login_header_title");
 
 
 
 
51
  /**/
52
  add_action ("admin_init", "ws_plugin__s2member_admin_lockout");
53
  add_action ("admin_init", "ws_plugin__s2member_general_ops_notice");
@@ -65,6 +71,9 @@ add_action ("edit_user_profile_update", "ws_plugin__s2member_users_list_update_c
65
  add_action ("personal_options_update", "ws_plugin__s2member_users_list_update_cols");
66
  /**/
67
  add_shortcode ("s2Member-PayPal-Button", "ws_plugin__s2member_paypal_button");
 
 
 
68
  /*
69
  Register the activation | de-activation routines.
70
  */
26
  add_action ("init", "ws_plugin__s2member_paypal_notify");
27
  add_action ("init", "ws_plugin__s2member_check_file_download_access");
28
  add_action ("init", "ws_plugin__s2member_handle_profile_modifications");
29
+ add_action ("init", "ws_plugin__s2member_delete_signup_tracking_cookie");
30
+ add_action ("init", "ws_plugin__s2member_delete_sp_tracking_cookie");
31
  /**/
32
  add_action ("template_redirect", "ws_plugin__s2member_check_ruri_level_access", 1);
33
  add_action ("template_redirect", "ws_plugin__s2member_check_catg_level_access", 1);
50
  add_action ("login_head", "ws_plugin__s2member_login_header_styles");
51
  add_filter ("login_headerurl", "ws_plugin__s2member_login_header_url");
52
  add_filter ("login_headertitle", "ws_plugin__s2member_login_header_title");
53
+ add_action ("login_form_register", "ws_plugin__s2member_display_signup_tracking_codes");
54
+ add_action ("login_form_login", "ws_plugin__s2member_display_signup_tracking_codes");
55
+ add_action ("wp_footer", "ws_plugin__s2member_display_signup_tracking_codes");
56
+ add_action ("wp_footer", "ws_plugin__s2member_display_sp_tracking_codes");
57
  /**/
58
  add_action ("admin_init", "ws_plugin__s2member_admin_lockout");
59
  add_action ("admin_init", "ws_plugin__s2member_general_ops_notice");
71
  add_action ("personal_options_update", "ws_plugin__s2member_users_list_update_cols");
72
  /**/
73
  add_shortcode ("s2Member-PayPal-Button", "ws_plugin__s2member_paypal_button");
74
+ /**/
75
+ add_filter ("cron_schedules", "ws_plugin__s2member_extend_cron_schedules");
76
+ add_action ("s2member_auto_eot_system", "ws_plugin__s2member_auto_eot_system");
77
  /*
78
  Register the activation | de-activation routines.
79
  */
includes/menu-pages/api-ops.inc.php CHANGED
@@ -36,7 +36,7 @@ echo '<div class="ws-menu-page-group" title="Signup Notifications">' . "\n";
36
  /**/
37
  echo '<div class="ws-menu-page-section ws-plugin--s2member-signup-notifications-section">' . "\n";
38
  echo '<h3>Signup Notification URLs ( optional )</h3>' . "\n";
39
- echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever a new subscription is created, you\'ll want to read this section. This is marked `Signup`, because the URLs that you list below, will be notified each time a Member signs up. Depending on your fee structure, this may include a first initial payment that establishes their subscription. This notification will only be triggered once for each Member. Signup Notifications are sent right after a Member signs up successfully through PayPal®, regardless of whether any money has actually been received. In other words, this notification is triggered anytime a Member signs up, even if you provided them with a free trial. Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN integration is already built into s2Member and remains active at all times. These Signup Notifications are an added layer of functionality, and they are completely optional; used primarily in affiliate program integration &amp; other back-office routines.</p>' . "\n";
40
  /**/
41
  echo '<table class="form-table">' . "\n";
42
  echo '<tbody>' . "\n";
@@ -52,31 +52,31 @@ echo '</tr>' . "\n";
52
  echo '<tr>' . "\n";
53
  /**/
54
  echo '<td>' . "\n";
55
- echo 'You can input multiple notification URLs by inserting one per line.<br />' . "\n";
56
  echo '<textarea name="ws_plugin__s2member_signup_notification_urls" id="ws-plugin--s2member-signup-notification-urls" rows="3" wrap="off">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_notification_urls"]) . '</textarea><br />' . "\n";
57
  echo 'Signup Notifications take place silently behind-the-scene, using a cURL connection. Each URL will be notified every time a new user signs up successfully through PayPal.<br /><br />' . "\n";
58
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
59
  echo '<ul>' . "\n";
60
- echo '<li><code>%%subscr_id%% = The PayPal® Subscription ID, which remains constant throughout any &amp; all future payments.</code> [ <a href="#" onclick="alert(\'There is one exception. If you are selling Lifetime ( non-recurring ) access, using a Buy It Now button; the %%subscr_id%% is actually set to the Transaction ID for the purchase.\\n\\nPayPal® does not provide a specific Subscription ID for Buy It Now purchases. Since Lifetime subscriptions are NOT recurring ( i.e. there is only ONE payment ), using the Transaction ID as the Subscription ID is a graceful way to deal with this minor conflict.\'); return false;">?</a> ]</li>' . "\n";
61
  echo '<li><code>%%initial%% = The Initial Fee charged during signup. If you offered a free trial, this will be 0.</code> [ <a href="#" onclick="alert(\'This will always represent the amount of money the Customer spent, whenever they initially signed up, no matter what. Even if that amount is 0.\\n\\nIf a Customer signs up, under the terms of a free trial period, this will be 0. So be careful using %%initial%% when you offer a free trial period, because a $0.00 sale amount could cause havoc with affiliate programs. If you\\\'re offering a free trial period, and you need to track sales through affiliate programs, you can either hard-code an amount; or use `Payment Notifications` instead.\'); return false;">?</a> ]</li>' . "\n";
62
- echo '<li><code>%%regular%% = The Regular Amount of the subscription. This value is always > 0, no matter what.</code> [ <a href="#" onclick="alert(\'This is how much the subscription costs after an initial period expires. The %%regular%% rate is always > 0. If you did not offer an initial period, %%initial%% and %%regular%% will be equal to the same thing.\'); return false;">?</a> ]</li>' . "\n";
63
- echo '<li><code>%%recurring%% = This is the amount that will be charged on a Recurring basis, or 0 if non-Recurring.</code> [ <a href="#" onclick="alert(\'If recurring payments have not been required, this will be equal to 0. That being said, %%regular%% &amp; %%recurring%% are usually the same value. This variable can be used in two different ways. You can use it to determine what the regular recurring rate is, or to determine whether the subscription will recur or not. If it is going to recur, %%recurring%% will be > 0.\\n\\nThe only time this is NOT equal to the %%regular%% rate, is when recurring payments are not required; and only a one-time regular rate applies. If you have trouble, try using the %%regular%% amount, or use the `Payment` Notifications instead of the `Signup` Notifications.\'); return false;">?</a> ]</li>' . "\n";
64
- echo '<li><code>%%first_name%% = The First Name of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
65
- echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
66
- echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased the membership subscription.</code></li>' . "\n";
67
- echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
68
- echo '<li><code>%%item_number%% = The Item Number ( colon separated <em>level:custom_capabilities</em> ) for the membership subscription.</code></li>' . "\n";
69
  echo '<li><code>%%item_name%% = The Item Name ( in other words, the associated membership Level Label that briefly describes the Item Number ).</code></li>' . "\n";
70
- echo '<li><code>%%initial_term%% = This is the term length of the initial period. This will be a numeric value, followed by a space, then a single letter.</code> [ <a href="#" onclick="alert(\'Here are some examples:\\n\\n%%initial_term%% = 1 D ( this means 1 Day )\\n%%initial_term%% = 1 M ( this means 1 Month )\\n%%initial_term%% = 1 Y ( this means 1 Year )\\n\\nThe initial period never recurs, so this only lasts for the term length specified, then it is over. If no initial period was even offered, the value of %%initial_term%% will just be: 0 D, meaning zero days.\'); return false;">?</a> ]</li>' . "\n";
71
- echo '<li><code>%%regular_term%% = This is the term length of the regular period. This will be a numeric value, followed by a space, then a single letter.</code> [ <a href="#" onclick="alert(\'Here are some examples:\\n\\n%%regular_term%% = 1 D ( this means 1 Day )\\n%%regular_term%% = 1 M ( this means 1 Month )\\n%%regular_term%% = 1 Y ( this means 1 Year )\\n%%regular_term%% = 1 L ( this means 1 Lifetime )\\n\\nThe regular term is usually recurring. So the regular term value represents the period ( or duration ) of each recurring period. If %%recurring%% = 0, then the regular term only applies once, because it is not recurring. So if it is not recurring, the value of %%regular_term%% simply represents how long their membership privileges are going to last after the %%initial_term%% has expired, if there was an initial term. The value of this variable ( %%regular_term%% ) will never be empty, it will always be at least: 1 D, meaning 1 day. No exceptions.\'); return false;">?</a> ]</li>' . "\n";
72
  echo '</ul>' . "\n";
73
  echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
74
  echo '<ul>' . "\n";
75
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
76
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
77
  echo '</ul>' . "\n";
78
- echo '<strong>This example uses cv1 to track a user\'s IP address:</strong><br />' . "\n";
79
- echo '<em>( The IP address can be referenced in your notification URL using %%cv1%% )</em><br />' . "\n";
80
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
81
  echo '</td>' . "\n";
82
  /**/
@@ -107,7 +107,7 @@ echo '</tr>' . "\n";
107
  echo '<tr>' . "\n";
108
  /**/
109
  echo '<td>' . "\n";
110
- echo 'You can input multiple notification URLs by inserting one per line.<br />' . "\n";
111
  echo '<textarea name="ws_plugin__s2member_registration_notification_urls" id="ws-plugin--s2member-registration-notification-urls" rows="3" wrap="off">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["registration_notification_urls"]) . '</textarea><br />' . "\n";
112
  echo 'Registration Notifications take place silently behind-the-scene, using a cURL connection. Each URL will be notified every time a new user registers a Username.<br /><br />' . "\n";
113
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
@@ -125,8 +125,8 @@ echo '<ul>' . "\n";
125
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
126
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
127
  echo '</ul>' . "\n";
128
- echo '<strong>This example uses cv1 to track a user\'s IP address:</strong><br />' . "\n";
129
- echo '<em>( The IP address can be referenced in your notification URL using %%cv1%% )</em><br />' . "\n";
130
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
131
  echo '</td>' . "\n";
132
  /**/
@@ -141,7 +141,7 @@ echo '<div class="ws-menu-page-group" title="Payment Notifications">' . "\n";
141
  /**/
142
  echo '<div class="ws-menu-page-section ws-plugin--s2member-payment-notifications-section">' . "\n";
143
  echo '<h3>Payment Notification URLs ( optional )</h3>' . "\n";
144
- echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever payment transactions take place, and/or for recurring payments, you\'ll want to read this section. This is marked `Payment`, because the URLs that you list below, will be notified each time an actual payment occurs. Depending on your fee structure, this may include a first initial payment that establishes a subscription. But more importantly, this will be triggered on all future payments that are received for the lifetime of the subscription. So unlike the `Signup` Notification, `Payment` Notifications take place whenever actual payments are received, instead of just once after signup is completed. If a payment is required during signup ( e.g. no free trial is being offered ), a Signup Notification will be triggered, and a Payment Notification will ALSO be triggered. In other words, a Payment Notification occurs anytime funds are received, no matter what. Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN integration is already built into s2Member and remains active at all times. These Payment Notifications are an added layer of functionality, and they are completely optional; used primarily in affiliate program integration &amp; other back-office routines.</p>' . "\n";
145
  /**/
146
  echo '<table class="form-table">' . "\n";
147
  echo '<tbody>' . "\n";
@@ -157,28 +157,28 @@ echo '</tr>' . "\n";
157
  echo '<tr>' . "\n";
158
  /**/
159
  echo '<td>' . "\n";
160
- echo 'You can input multiple notification URLs by inserting one per line.<br />' . "\n";
161
  echo '<textarea name="ws_plugin__s2member_payment_notification_urls" id="ws-plugin--s2member-payment-notification-urls" rows="3" wrap="off">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["payment_notification_urls"]) . '</textarea><br />' . "\n";
162
  echo 'Payment Notifications take place silently behind-the-scene, using a cURL connection. Each URL will be notified every time an initial and/or recurring payment occurs.<br /><br />' . "\n";
163
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
164
  echo '<ul>' . "\n";
165
- echo '<li><code>%%subscr_id%% = The PayPal® Subscription ID, which remains constant throughout any &amp; all future payments.</code> [ <a href="#" onclick="alert(\'There is one exception. If you are selling Lifetime ( non-recurring ) access, using a Buy It Now button; the %%subscr_id%% is actually set to the Transaction ID for the payment.\\n\\nPayPal® does not provide a specific Subscription ID for Buy It Now purchases. Since Lifetime subscriptions are NOT recurring ( i.e. there is only ONE payment ), using the Transaction ID as the Subscription ID is a graceful way to deal with this minor conflict.\'); return false;">?</a> ]</li>' . "\n";
166
  echo '<li><code>%%txn_id%% = The PayPal® unique Transaction ID, which is always unique for each payment received.</code></li>' . "\n";
167
  echo '<li><code>%%amount%% = The Amount of the payment. Most affiliate programs calculate commissions from this.</code></li>' . "\n";
168
- echo '<li><code>%%first_name%% = The First Name of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
169
- echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
170
- echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased the membership subscription.</code></li>' . "\n";
171
- echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
172
- echo '<li><code>%%item_number%% = The Item Number ( colon separated <em>level:custom_capabilities</em> ) that the payment is for.</code></li>' . "\n";
173
- echo '<li><code>%%item_name%% = The Item Name ( in other words, the associated membership Level Label that briefly describes the item number ).</code></li>' . "\n";
174
  echo '</ul>' . "\n";
175
  echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
176
  echo '<ul>' . "\n";
177
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
178
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
179
  echo '</ul>' . "\n";
180
- echo '<strong>This example uses cv1 to track a user\'s IP address:</strong><br />' . "\n";
181
- echo '<em>( The IP address can be referenced in your notification URL using %%cv1%% )</em><br />' . "\n";
182
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
183
  echo '</td>' . "\n";
184
  /**/
@@ -193,9 +193,9 @@ echo '<div class="ws-menu-page-group" title="EOT/Deletion Notifications">' . "\n
193
  /**/
194
  echo '<div class="ws-menu-page-section ws-plugin--s2member-eot-deletion-notifications-section">' . "\n";
195
  echo '<h3>EOT/Deletion Notification URLs ( optional )</h3>' . "\n";
196
- echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever subscriptions have ended ( and a Member is demoted to a Free Subscriber ), or when an account is deleted from the system, you\'ll want to read this section. This is marked `EOT/Deletion`, because the URLs that you list below, will be notified in both cases. EOT = End Of Term. An EOT is triggered anytime you cancel or refund a subscription via PayPal®, or if a Member cancels their own subscription through PayPal®, fails to make payments, etc. In other words, anytime a subscription reaches the end of its term, because you issue a refund, a chargeback occurs, a cancellation occurs, or failed payments force PayPal® to end their subscription, this is triggered.</p>' . "\n";
197
- echo '<p>EOTs are not necessarily triggered immediately after a cancellation takes place though. For example, if a Member signs up for a monthly subscription on Jan 1st, and then cancels their subscription on Jan 15th; technically, they should still be allowed to access your site for another 15 days, and then, on Feb 1st, the time they paid for has completely elapsed. That is when their account is automatically demoted to a Free Subscriber, or deleted from the system completely ( based on your configuration ), and an EOT Notification is triggered. That being said, there are cases when an EOT is triggered immediately. For instance, if too many of their subscription payments fail at PayPal® ( more than 2 in a row ), an EOT will be issued immediately, also resulting in the automatic demotion or deletion of their account. If you log into your PayPal® account and issue a refund to an unhappy Customer, their account will automatically be demoted or deleted, and an EOT is triggered immediately.</p>' . "\n";
198
- echo '<p>Manual Deletions are the other case in which these Notifications will be triggered. If you delete an account manually from within your WordPress® Dashboard, your affiliate software will be notified automatically through this notification. So the two events are an EOT and/or a manual Deletion. Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN integration is already built into s2Member and remains active at all times. These EOT/Deletion Notifications are an added layer of functionality, and they are completely optional; used primarily in affiliate program integration &amp; other back-office routines.</p>' . "\n";
199
  /**/
200
  echo '<table class="form-table">' . "\n";
201
  echo '<tbody>' . "\n";
@@ -211,12 +211,12 @@ echo '</tr>' . "\n";
211
  echo '<tr>' . "\n";
212
  /**/
213
  echo '<td>' . "\n";
214
- echo 'You can input multiple notification URLs by inserting one per line.<br />' . "\n";
215
  echo '<textarea name="ws_plugin__s2member_eot_del_notification_urls" id="ws-plugin--s2member-eot-del-notification-urls" rows="3" wrap="off">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_del_notification_urls"]) . '</textarea><br />' . "\n";
216
- echo 'EOT/Deletion Notifications take place silently behind-the-scene, using a cURL connection. Each URL will be notified every time a subscription reaches the end of its term or is deleted.<br /><br />' . "\n";
217
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
218
  echo '<ul>' . "\n";
219
- echo '<li><code>%%subscr_id%% = The PayPal® Subscription ID, which remained constant throughout the lifetime of the membership.</code> [ <a href="#" onclick="alert(\'There is one exception. If you are selling Lifetime ( non-recurring ) access, using a Buy It Now button; the %%subscr_id%% is actually set to the original Transaction ID for the purchase.\\n\\nPayPal® does not provide a specific Subscription ID for Buy It Now purchases. Since Lifetime subscriptions are NOT recurring ( i.e. there was only ONE payment ), using the Transaction ID as the Subscription ID is a graceful way to deal with this minor conflict.\'); return false;">?</a> ]</li>' . "\n";
220
  echo '<li><code>%%user_first_name%% = The First Name listed on their User account. This might be different than what is on file at PayPal®.</code></li>' . "\n";
221
  echo '<li><code>%%user_last_name%% = The Last Name listed on their User account. This might be different than what is on file at PayPal®.</code></li>' . "\n";
222
  echo '<li><code>%%user_full_name%% = The Full Name listed on their User account. This might be different than what is on file at PayPal®.</code></li>' . "\n";
@@ -227,8 +227,8 @@ echo '<ul>' . "\n";
227
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
228
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
229
  echo '</ul>' . "\n";
230
- echo '<strong>This example uses cv1 to track a user\'s IP address:</strong><br />' . "\n";
231
- echo '<em>( The IP address can be referenced in your notification URL using %%cv1%% )</em><br />' . "\n";
232
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
233
  echo '</td>' . "\n";
234
  /**/
@@ -243,7 +243,7 @@ echo '<div class="ws-menu-page-group" title="Refund/Reversal Notifications">' .
243
  /**/
244
  echo '<div class="ws-menu-page-section ws-plugin--s2member-refund-reversal-notifications-section">' . "\n";
245
  echo '<h3>Refund/Reversal Notification URLs ( optional )</h3>' . "\n";
246
- echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever subscriptions have been refunded or reversed ( e.g. charged back to you ), you\'ll want to read this section. This is marked `Refund/Reversal`, because the URLs that you list below, will ONLY be notified in those specific cases, as opposed to the EOT Notifications, which are all-inclusive. This is very similar to the EOT/Deletion described above. But, there is an important distinction. EOT includes cancellations, expirations, failed payments, refunds, chargebacks, etc, etc. In other words, ANY time a deletion or End Of Term action takes place.</p>' . "\n";
247
  echo '<p>So the distinction is that Refund/Reversal Notifications are ONLY sent under these specific circumstances: 1. You log into your PayPal® account and refund a payment that is associated with a Subscription. 2. The Customer complains to PayPal® and a chargeback occurs, forcing a Reversal. In both of these cases, an EOT/Deletion Notification will be sent ( as described above ), but since EOT is a more broad Notification, the Refund/Reversal Notification is here so you can nail down specific back-office operations in these two specific scenarios. Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN integration is already built into s2Member and remains active at all times. These Refund/Reversal Notifications are an added layer of functionality, and they are completely optional; used primarily in affiliate program integration &amp; other back-office routines.</p>' . "\n";
248
  /**/
249
  echo '<table class="form-table">' . "\n";
@@ -260,28 +260,28 @@ echo '</tr>' . "\n";
260
  echo '<tr>' . "\n";
261
  /**/
262
  echo '<td>' . "\n";
263
- echo 'You can input multiple notification URLs by inserting one per line.<br />' . "\n";
264
  echo '<textarea name="ws_plugin__s2member_ref_rev_notification_urls" id="ws-plugin--s2member-ref-rev-notification-urls" rows="3" wrap="off">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["ref_rev_notification_urls"]) . '</textarea><br />' . "\n";
265
  echo 'Refund/Reversal Notifications take place silently behind-the-scene, using a cURL connection. Each URL will be notified every time a payment is refunded through PayPal® or a chargeback occurs.<br /><br />' . "\n";
266
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
267
  echo '<ul>' . "\n";
268
- echo '<li><code>%%subscr_id%% = The PayPal® Subscription ID, which remained constant throughout the lifetime of the membership.</code> [ <a href="#" onclick="alert(\'There is one exception. If you are selling Lifetime ( non-recurring ) access, using a Buy It Now button; the %%subscr_id%% is actually set to the original Transaction ID for the purchase.\\n\\nPayPal® does not provide a specific Subscription ID for Buy It Now purchases. Since Lifetime subscriptions are NOT recurring ( i.e. there was only ONE payment ), using the Transaction ID as the Subscription ID is a graceful way to deal with this minor conflict.\'); return false;">?</a> ]</li>' . "\n";
269
  echo '<li><code>%%parent_txn_id%% = The PayPal® Transaction ID, associated with the original payment that is being refunded/reversed.</code></li>' . "\n";
270
  echo '<li><code>%%-amount%% = The Negative Amount of the payment, that was refunded or reversed back to the Customer.</code></li>' . "\n";
271
- echo '<li><code>%%first_name%% = The First Name of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
272
- echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
273
- echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased the membership subscription.</code></li>' . "\n";
274
- echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
275
- echo '<li><code>%%item_number%% = The Item Number ( colon separated <em>level:custom_capabilities</em> ) that the payment was for.</code></li>' . "\n";
276
- echo '<li><code>%%item_name%% = The Item Name ( in other words, the associated membership Level Label that briefly describes the item number ).</code></li>' . "\n";
277
  echo '</ul>' . "\n";
278
  echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
279
  echo '<ul>' . "\n";
280
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
281
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
282
  echo '</ul>' . "\n";
283
- echo '<strong>This example uses cv1 to track a user\'s IP address:</strong><br />' . "\n";
284
- echo '<em>( The IP address can be referenced in your notification URL using %%cv1%% )</em><br />' . "\n";
285
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
286
  echo '</td>' . "\n";
287
  /**/
@@ -292,11 +292,11 @@ echo '</div>' . "\n";
292
  /**/
293
  echo '</div>' . "\n";
294
  /**/
295
- echo '<div class="ws-menu-page-group" title="Single-Page Access Notifications">' . "\n";
296
  /**/
297
  echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-notifications-section">' . "\n";
298
- echo '<h3>Single-Page Access Notification URLs ( optional )</h3>' . "\n";
299
- echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever Single-Page transactions take place, you\'ll want to read this section. This is marked `Single-Page`, because the URLs that you list below, will be notified each time a payment occurs, specifically for a Single-Page sale. This is the only Notification that is sent for Single-Page Access. All of the other API Notifications are designed for Membership Level Access. Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN integration is already built into s2Member and remains active at all times. These Payment Notifications are an added layer of functionality, and they are completely optional; used primarily in affiliate program integration &amp; other back-office routines.</p>' . "\n";
300
  /**/
301
  echo '<table class="form-table">' . "\n";
302
  echo '<tbody>' . "\n";
@@ -304,7 +304,7 @@ echo '<tr>' . "\n";
304
  /**/
305
  echo '<th>' . "\n";
306
  echo '<label for="ws-plugin--s2member-sp-notification-urls">' . "\n";
307
- echo 'Single-Page Notification URLs:' . "\n";
308
  echo '</label>' . "\n";
309
  echo '</th>' . "\n";
310
  /**/
@@ -312,20 +312,20 @@ echo '</tr>' . "\n";
312
  echo '<tr>' . "\n";
313
  /**/
314
  echo '<td>' . "\n";
315
- echo 'You can input multiple notification URLs by inserting one per line.<br />' . "\n";
316
  echo '<textarea name="ws_plugin__s2member_sp_notification_urls" id="ws-plugin--s2member-sp-notification-urls" rows="3" wrap="off">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_notification_urls"]) . '</textarea><br />' . "\n";
317
- echo 'Single-Page Notifications take place silently behind-the-scene, using a cURL connection. Each URL will be notified every time a sale occurs.<br /><br />' . "\n";
318
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
319
  echo '<ul>' . "\n";
320
  echo '<li><code>%%sp_access_url%% = The full URL ( generated by s2Member ) where the Customer can gain access.</code></li>' . "\n";
321
  echo '<li><code>%%sp_access_exp%% = Human readable expiration for %%sp_access_url%%. Ex: <em>( link expires in %%sp_access_exp%% )</em>.</code></li>' . "\n";
322
  echo '<li><code>%%txn_id%% = The PayPal® Transaction ID. PayPal® assigns a unique identifier for every purchase.</code></li>' . "\n";
323
  echo '<li><code>%%amount%% = The full Amount of the sale. Most affiliate programs calculate commissions from this.</code></li>' . "\n";
324
- echo '<li><code>%%first_name%% = The First Name of the Customer who purchased Single-Page Access through PayPal®.</code></li>' . "\n";
325
- echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased Single-Page Access through PayPal®.</code></li>' . "\n";
326
- echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased Single-Page Access.</code></li>' . "\n";
327
- echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased Single-Page Access through PayPal®.</code></li>' . "\n";
328
- echo '<li><code>%%item_number%% = The Item Number. Ex: <em>sp:13:72</em> ( sp:page_ID:expiration_hours ).</code></li>' . "\n";
329
  echo '<li><code>%%item_name%% = The Item Name. In other words, a brief description, detailing what this purchase was for.</code></li>' . "\n";
330
  echo '</ul>' . "\n";
331
  echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
@@ -333,8 +333,8 @@ echo '<ul>' . "\n";
333
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
334
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
335
  echo '</ul>' . "\n";
336
- echo '<strong>This example uses cv1 to track a user\'s IP address:</strong><br />' . "\n";
337
- echo '<em>( The IP address can be referenced in your notification URL using %%cv1%% )</em><br />' . "\n";
338
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
339
  echo '</td>' . "\n";
340
  /**/
36
  /**/
37
  echo '<div class="ws-menu-page-section ws-plugin--s2member-signup-notifications-section">' . "\n";
38
  echo '<h3>Signup Notification URLs ( optional )</h3>' . "\n";
39
+ echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever a new Subscription is created, you\'ll want to read this section. This is marked `Signup`, because the URLs that you list below, will be notified each time a Member signs up. Depending on your fee structure, this may include a first initial payment that establishes their Subscription. This Notification will only be triggered once for each Member. Signup Notifications are sent right after a Member signs up successfully through PayPal®, regardless of whether any money has actually been received. In other words, this Notification is triggered anytime a Member signs up, even if you provided them with a free trial. Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN integration is already built into s2Member and remains active at all times. These Signup Notifications are an added layer of functionality, and they are completely optional; used primarily in affiliate program integration &amp; other back-office routines.</p>' . "\n";
40
  /**/
41
  echo '<table class="form-table">' . "\n";
42
  echo '<tbody>' . "\n";
52
  echo '<tr>' . "\n";
53
  /**/
54
  echo '<td>' . "\n";
55
+ echo 'You can input multiple Notification URLs by inserting one per line.<br />' . "\n";
56
  echo '<textarea name="ws_plugin__s2member_signup_notification_urls" id="ws-plugin--s2member-signup-notification-urls" rows="3" wrap="off">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_notification_urls"]) . '</textarea><br />' . "\n";
57
  echo 'Signup Notifications take place silently behind-the-scene, using a cURL connection. Each URL will be notified every time a new user signs up successfully through PayPal.<br /><br />' . "\n";
58
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
59
  echo '<ul>' . "\n";
60
+ echo '<li><code>%%subscr_id%% = The PayPal® Subscription ID, which remains constant throughout any &amp; all future payments.</code> [ <a href="#" onclick="alert(\'There is one exception. If you are selling Lifetime or Fixed-Term ( non-recurring ) access, using a Buy It Now button; the %%subscr_id%% is actually set to the Transaction ID for the purchase.\\n\\nPayPal® does not provide a specific Subscription ID for Buy It Now purchases. Since Lifetime &amp; Fixed-Term Subscriptions are NOT recurring ( i.e. there is only ONE payment ), using the Transaction ID as the Subscription ID is a graceful way to deal with this minor conflict.\'); return false;">?</a> ]</li>' . "\n";
61
  echo '<li><code>%%initial%% = The Initial Fee charged during signup. If you offered a free trial, this will be 0.</code> [ <a href="#" onclick="alert(\'This will always represent the amount of money the Customer spent, whenever they initially signed up, no matter what. Even if that amount is 0.\\n\\nIf a Customer signs up, under the terms of a free trial period, this will be 0. So be careful using %%initial%% when you offer a free trial period, because a $0.00 sale amount could cause havoc with affiliate programs. If you\\\'re offering a free trial period, and you need to track sales through affiliate programs, you can either hard-code an amount; or use `Payment Notifications` instead.\'); return false;">?</a> ]</li>' . "\n";
62
+ echo '<li><code>%%regular%% = The Regular Amount of the Subscription. This value is always > 0, no matter what.</code> [ <a href="#" onclick="alert(\'This is how much the Subscription costs after an initial period expires. The %%regular%% rate is always > 0. If you did not offer an initial period, %%initial%% and %%regular%% will be equal to the same thing.\'); return false;">?</a> ]</li>' . "\n";
63
+ echo '<li><code>%%recurring%% = This is the amount that will be charged on a Recurring basis, or 0 if non-Recurring.</code> [ <a href="#" onclick="alert(\'If recurring payments have not been required, this will be equal to 0. That being said, %%regular%% &amp; %%recurring%% are usually the same value. This variable can be used in two different ways. You can use it to determine what the regular recurring rate is, or to determine whether the Subscription will recur or not. If it is going to recur, %%recurring%% will be > 0.\\n\\nThe only time this is NOT equal to the %%regular%% rate, is when recurring payments are not required; and only a one-time regular rate applies. If you have trouble, try using the %%regular%% amount, or use the `Payment` Notifications instead of the `Signup` Notifications.\'); return false;">?</a> ]</li>' . "\n";
64
+ echo '<li><code>%%first_name%% = The First Name of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
65
+ echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
66
+ echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased the Membership Subscription.</code></li>' . "\n";
67
+ echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
68
+ echo '<li><code>%%item_number%% = The Item Number ( colon separated <em>level:custom_capabilities:fixed term</em> ) for the Membership Subscription.</code></li>' . "\n";
69
  echo '<li><code>%%item_name%% = The Item Name ( in other words, the associated membership Level Label that briefly describes the Item Number ).</code></li>' . "\n";
70
+ echo '<li><code>%%initial_term%% = This is the term length of the initial period. This will be a numeric value, followed by a space, then a single letter.</code> [ <a href="#" onclick="alert(\'Here are some examples:\\n\\n%%initial_term%% = 1 D ( this means 1 Day )\\n%%initial_term%% = 1 W ( this means 1 Week )\\n%%initial_term%% = 1 M ( this means 1 Month )\\n%%initial_term%% = 1 Y ( this means 1 Year )\\n\\nThe initial period never recurs, so this only lasts for the term length specified, then it is over. If no initial period was even offered, the value of %%initial_term%% will just be: 0 D, meaning zero days.\'); return false;">?</a> ]</li>' . "\n";
71
+ echo '<li><code>%%regular_term%% = This is the term length of the regular period. This will be a numeric value, followed by a space, then a single letter.</code> [ <a href="#" onclick="alert(\'Here are some examples:\\n\\n%%regular_term%% = 1 D ( this means 1 Day )\\n%%regular_term%% = 1 W ( this means 1 Week )\\n%%regular_term%% = 1 M ( this means 1 Month )\\n%%regular_term%% = 1 Y ( this means 1 Year )\\n%%regular_term%% = 1 L ( this means 1 Lifetime )\\n\\nThe regular term is usually recurring. So the regular term value represents the period ( or duration ) of each recurring period. If %%recurring%% = 0, then the regular term only applies once, because it is not recurring. So if it is not recurring, the value of %%regular_term%% simply represents how long their membership privileges are going to last after the %%initial_term%% has expired, if there was an initial term. The value of this variable ( %%regular_term%% ) will never be empty, it will always be at least: 1 D, meaning 1 day. No exceptions.\'); return false;">?</a> ]</li>' . "\n";
72
  echo '</ul>' . "\n";
73
  echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
74
  echo '<ul>' . "\n";
75
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
76
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
77
  echo '</ul>' . "\n";
78
+ echo '<strong>This example uses cv1 to track a User\'s IP address:</strong><br />' . "\n";
79
+ echo '<em>( The IP address could be referenced in your Notification URL using %%cv1%% )</em><br />' . "\n";
80
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
81
  echo '</td>' . "\n";
82
  /**/
107
  echo '<tr>' . "\n";
108
  /**/
109
  echo '<td>' . "\n";
110
+ echo 'You can input multiple Notification URLs by inserting one per line.<br />' . "\n";
111
  echo '<textarea name="ws_plugin__s2member_registration_notification_urls" id="ws-plugin--s2member-registration-notification-urls" rows="3" wrap="off">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["registration_notification_urls"]) . '</textarea><br />' . "\n";
112
  echo 'Registration Notifications take place silently behind-the-scene, using a cURL connection. Each URL will be notified every time a new user registers a Username.<br /><br />' . "\n";
113
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
125
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
126
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
127
  echo '</ul>' . "\n";
128
+ echo '<strong>This example uses cv1 to track a User\'s IP address:</strong><br />' . "\n";
129
+ echo '<em>( The IP address could be referenced in your Notification URL using %%cv1%% )</em><br />' . "\n";
130
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
131
  echo '</td>' . "\n";
132
  /**/
141
  /**/
142
  echo '<div class="ws-menu-page-section ws-plugin--s2member-payment-notifications-section">' . "\n";
143
  echo '<h3>Payment Notification URLs ( optional )</h3>' . "\n";
144
+ echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever payment transactions take place, and/or for recurring payments, you\'ll want to read this section. This is marked `Payment`, because the URLs that you list below, will be notified each time an actual payment occurs. Depending on your fee structure, this may include a first initial payment that establishes a Subscription. But more importantly, this will be triggered on all future payments that are received for the lifetime of the Subscription. So unlike the `Signup` Notification, `Payment` Notifications take place whenever actual payments are received, instead of just once after signup is completed. If a payment is required during signup ( e.g. no free trial is being offered ), a Signup Notification will be triggered, and a Payment Notification will ALSO be triggered. In other words, a Payment Notification occurs anytime funds are received, no matter what. Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN integration is already built into s2Member and remains active at all times. These Payment Notifications are an added layer of functionality, and they are completely optional; used primarily in affiliate program integration &amp; other back-office routines.</p>' . "\n";
145
  /**/
146
  echo '<table class="form-table">' . "\n";
147
  echo '<tbody>' . "\n";
157
  echo '<tr>' . "\n";
158
  /**/
159
  echo '<td>' . "\n";
160
+ echo 'You can input multiple Notification URLs by inserting one per line.<br />' . "\n";
161
  echo '<textarea name="ws_plugin__s2member_payment_notification_urls" id="ws-plugin--s2member-payment-notification-urls" rows="3" wrap="off">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["payment_notification_urls"]) . '</textarea><br />' . "\n";
162
  echo 'Payment Notifications take place silently behind-the-scene, using a cURL connection. Each URL will be notified every time an initial and/or recurring payment occurs.<br /><br />' . "\n";
163
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
164
  echo '<ul>' . "\n";
165
+ echo '<li><code>%%subscr_id%% = The PayPal® Subscription ID, which remains constant throughout any &amp; all future payments.</code> [ <a href="#" onclick="alert(\'There is one exception. If you are selling Lifetime or Fixed-Term ( non-recurring ) access, using a Buy It Now button; the %%subscr_id%% is actually set to the Transaction ID for the payment.\\n\\nPayPal® does not provide a specific Subscription ID for Buy It Now purchases. Since Lifetime &amp; Fixed-Term Subscriptions are NOT recurring ( i.e. there is only ONE payment ), using the Transaction ID as the Subscription ID is a graceful way to deal with this minor conflict.\'); return false;">?</a> ]</li>' . "\n";
166
  echo '<li><code>%%txn_id%% = The PayPal® unique Transaction ID, which is always unique for each payment received.</code></li>' . "\n";
167
  echo '<li><code>%%amount%% = The Amount of the payment. Most affiliate programs calculate commissions from this.</code></li>' . "\n";
168
+ echo '<li><code>%%first_name%% = The First Name of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
169
+ echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
170
+ echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased the Membership Subscription.</code></li>' . "\n";
171
+ echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
172
+ echo '<li><code>%%item_number%% = The Item Number ( colon separated <em>level:custom_capabilities:fixed term</em> ) that the payment is for.</code></li>' . "\n";
173
+ echo '<li><code>%%item_name%% = The Item Name ( in other words, the associated membership Level Label that briefly describes the Item Number ).</code></li>' . "\n";
174
  echo '</ul>' . "\n";
175
  echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
176
  echo '<ul>' . "\n";
177
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
178
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
179
  echo '</ul>' . "\n";
180
+ echo '<strong>This example uses cv1 to track a User\'s IP address:</strong><br />' . "\n";
181
+ echo '<em>( The IP address could be referenced in your Notification URL using %%cv1%% )</em><br />' . "\n";
182
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
183
  echo '</td>' . "\n";
184
  /**/
193
  /**/
194
  echo '<div class="ws-menu-page-section ws-plugin--s2member-eot-deletion-notifications-section">' . "\n";
195
  echo '<h3>EOT/Deletion Notification URLs ( optional )</h3>' . "\n";
196
+ echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever Subscriptions have ended ( and a Member is demoted to a Free Subscriber ), or when an account is deleted from the system, you\'ll want to read this section. This is marked `EOT/Deletion`, because the URLs that you list below, will be notified in both cases. EOT = End Of Term. An EOT is triggered <em>immediately</em> when you refund a Customer, when a Customer forces a chargeback to occur, or when a PayPal® Subscription ends naturally ( i.e. expires ), and the PayPal® IPN service sends s2Member a <code>subscr_eot</code> response. Delayed EOTs occur after a cancellation, either as a result of you cancelling a Customer\'s Subscription, or a Customer cancelling their own Subscription through PayPal®. A cancellation usually results in a delayed EOT, because a cancellation does not always warrant an immediate EOT; there could still be time left on their Subscription.</p>' . "\n";
197
+ echo '<p>Manual Deletions will trigger an immediate Notification. If you delete an account manually from within your WordPress® Dashboard, your URLs can be notified automatically through this system. So the two events are an EOT and/or a Manual Deletion. Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN integration is already built into s2Member and remains active at all times. These EOT/Deletion Notifications are an added layer of functionality, and they are completely optional; used primarily in affiliate program integration &amp; other back-office routines.</p>' . "\n";
198
+ echo '<p><em><strong>*Some Hairy Details*</strong> There might be times whenever you notice that a Members\'s Subscription has been cancelled through PayPal®... but, s2Member continues allowing the User access to your site as a paid Member. Please don\'t be confused by this... in 99.9% of these cases, the reason for this is legitimate. s2Member will only remove the User\'s membership privileges when PayPal® sends a <code>subscr_eot</code> notification via the IPN service, a refund occurs, a chargeback occurs, or when a cancellation occurs - which would later result in a delayed Auto-EOT by s2Member. s2Member will not process an EOT until the User has completely used up the time they paid for. In other words, if a User signs up for a monthly Subscription on Jan 1st, and then cancels their Subscription on Jan 15th; technically, they should still be allowed to access the site for another 15 days, and then on Feb 1st, the time they paid for has completely elapsed. At that time, s2Member will remove their membership privileges; by either demoting them to a Free Subscriber, or deleting their account from the system ( based on your configuration ). s2Member also calculates one extra day ( 24 hours ) into its equation, just to make sure access is not removed sooner than a Customer might expect.</em></p>' . "\n";
199
  /**/
200
  echo '<table class="form-table">' . "\n";
201
  echo '<tbody>' . "\n";
211
  echo '<tr>' . "\n";
212
  /**/
213
  echo '<td>' . "\n";
214
+ echo 'You can input multiple Notification URLs by inserting one per line.<br />' . "\n";
215
  echo '<textarea name="ws_plugin__s2member_eot_del_notification_urls" id="ws-plugin--s2member-eot-del-notification-urls" rows="3" wrap="off">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_del_notification_urls"]) . '</textarea><br />' . "\n";
216
+ echo 'EOT/Deletion Notifications take place silently behind-the-scene, using a cURL connection. Each URL will be notified every time a Subscription hits an EOT, or is deleted.<br /><br />' . "\n";
217
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
218
  echo '<ul>' . "\n";
219
+ echo '<li><code>%%subscr_id%% = The PayPal® Subscription ID, which remained constant throughout the lifetime of the membership.</code> [ <a href="#" onclick="alert(\'There is one exception. If you are selling Lifetime or Fixed-Term ( non-recurring ) access, using a Buy It Now button; the %%subscr_id%% is actually set to the original Transaction ID for the purchase.\\n\\nPayPal® does not provide a specific Subscription ID for Buy It Now purchases. Since Lifetime &amp; Fixed-Term Subscriptions are NOT recurring ( i.e. there was only ONE payment ), using the Transaction ID as the Subscription ID is a graceful way to deal with this minor conflict.\'); return false;">?</a> ]</li>' . "\n";
220
  echo '<li><code>%%user_first_name%% = The First Name listed on their User account. This might be different than what is on file at PayPal®.</code></li>' . "\n";
221
  echo '<li><code>%%user_last_name%% = The Last Name listed on their User account. This might be different than what is on file at PayPal®.</code></li>' . "\n";
222
  echo '<li><code>%%user_full_name%% = The Full Name listed on their User account. This might be different than what is on file at PayPal®.</code></li>' . "\n";
227
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
228
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
229
  echo '</ul>' . "\n";
230
+ echo '<strong>This example uses cv1 to track a User\'s IP address:</strong><br />' . "\n";
231
+ echo '<em>( The IP address could be referenced in your Notification URL using %%cv1%% )</em><br />' . "\n";
232
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
233
  echo '</td>' . "\n";
234
  /**/
243
  /**/
244
  echo '<div class="ws-menu-page-section ws-plugin--s2member-refund-reversal-notifications-section">' . "\n";
245
  echo '<h3>Refund/Reversal Notification URLs ( optional )</h3>' . "\n";
246
+ echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever Subscriptions have been refunded or reversed ( i.e. charged back to you ), you\'ll want to read this section. This is marked `Refund/Reversal`, because the URLs that you list below, will ONLY be notified in those specific cases, as opposed to the EOT Notifications, which are all-inclusive. This is very similar to the EOT/Deletion described above. But, there is an important distinction. EOT includes cancellations, expirations, failed payments, refunds, chargebacks, etc, etc. In other words, ANY time a deletion or End Of Term action takes place.</p>' . "\n";
247
  echo '<p>So the distinction is that Refund/Reversal Notifications are ONLY sent under these specific circumstances: 1. You log into your PayPal® account and refund a payment that is associated with a Subscription. 2. The Customer complains to PayPal® and a chargeback occurs, forcing a Reversal. In both of these cases, an EOT/Deletion Notification will be sent ( as described above ), but since EOT is a more broad Notification, the Refund/Reversal Notification is here so you can nail down specific back-office operations in these two specific scenarios. Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN integration is already built into s2Member and remains active at all times. These Refund/Reversal Notifications are an added layer of functionality, and they are completely optional; used primarily in affiliate program integration &amp; other back-office routines.</p>' . "\n";
248
  /**/
249
  echo '<table class="form-table">' . "\n";
260
  echo '<tr>' . "\n";
261
  /**/
262
  echo '<td>' . "\n";
263
+ echo 'You can input multiple Notification URLs by inserting one per line.<br />' . "\n";
264
  echo '<textarea name="ws_plugin__s2member_ref_rev_notification_urls" id="ws-plugin--s2member-ref-rev-notification-urls" rows="3" wrap="off">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["ref_rev_notification_urls"]) . '</textarea><br />' . "\n";
265
  echo 'Refund/Reversal Notifications take place silently behind-the-scene, using a cURL connection. Each URL will be notified every time a payment is refunded through PayPal® or a chargeback occurs.<br /><br />' . "\n";
266
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
267
  echo '<ul>' . "\n";
268
+ echo '<li><code>%%subscr_id%% = The PayPal® Subscription ID, which remained constant throughout the lifetime of the membership.</code> [ <a href="#" onclick="alert(\'There is one exception. If you are selling Lifetime or Fixed-Term ( non-recurring ) access, using a Buy It Now button; the %%subscr_id%% is actually set to the original Transaction ID for the purchase.\\n\\nPayPal® does not provide a specific Subscription ID for Buy It Now purchases. Since Lifetime &amp; Fixed-Term Subscriptions are NOT recurring ( i.e. there was only ONE payment ), using the Transaction ID as the Subscription ID is a graceful way to deal with this minor conflict.\'); return false;">?</a> ]</li>' . "\n";
269
  echo '<li><code>%%parent_txn_id%% = The PayPal® Transaction ID, associated with the original payment that is being refunded/reversed.</code></li>' . "\n";
270
  echo '<li><code>%%-amount%% = The Negative Amount of the payment, that was refunded or reversed back to the Customer.</code></li>' . "\n";
271
+ echo '<li><code>%%first_name%% = The First Name of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
272
+ echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
273
+ echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased the Membership Subscription.</code></li>' . "\n";
274
+ echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
275
+ echo '<li><code>%%item_number%% = The Item Number ( colon separated <em>level:custom_capabilities:fixed term</em> ) that the payment was for.</code></li>' . "\n";
276
+ echo '<li><code>%%item_name%% = The Item Name ( in other words, the associated membership Level Label that briefly describes the Item Number ).</code></li>' . "\n";
277
  echo '</ul>' . "\n";
278
  echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
279
  echo '<ul>' . "\n";
280
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
281
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
282
  echo '</ul>' . "\n";
283
+ echo '<strong>This example uses cv1 to track a User\'s IP address:</strong><br />' . "\n";
284
+ echo '<em>( The IP address could be referenced in your Notification URL using %%cv1%% )</em><br />' . "\n";
285
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
286
  echo '</td>' . "\n";
287
  /**/
292
  /**/
293
  echo '</div>' . "\n";
294
  /**/
295
+ echo '<div class="ws-menu-page-group" title="Specific Post/Page Access Notifications">' . "\n";
296
  /**/
297
  echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-notifications-section">' . "\n";
298
+ echo '<h3>Specific Post/Page Access Notification URLs ( optional )</h3>' . "\n";
299
+ echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever Specific Post/Page transactions take place, you\'ll want to read this section. This is marked `Specific Post/Page`, because the URLs that you list below, will be notified each time a payment occurs, for access to a Specific Post/Page sale. This is the only Notification that is sent for Specific Post/Page Access. All of the other API Notifications are designed for Membership Level Access. Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN integration is already built into s2Member and remains active at all times. These Payment Notifications are an added layer of functionality, and they are completely optional; used primarily in affiliate program integration &amp; other back-office routines.</p>' . "\n";
300
  /**/
301
  echo '<table class="form-table">' . "\n";
302
  echo '<tbody>' . "\n";
304
  /**/
305
  echo '<th>' . "\n";
306
  echo '<label for="ws-plugin--s2member-sp-notification-urls">' . "\n";
307
+ echo 'Specific Post/Page Notification URLs:' . "\n";
308
  echo '</label>' . "\n";
309
  echo '</th>' . "\n";
310
  /**/
312
  echo '<tr>' . "\n";
313
  /**/
314
  echo '<td>' . "\n";
315
+ echo 'You can input multiple Notification URLs by inserting one per line.<br />' . "\n";
316
  echo '<textarea name="ws_plugin__s2member_sp_notification_urls" id="ws-plugin--s2member-sp-notification-urls" rows="3" wrap="off">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_notification_urls"]) . '</textarea><br />' . "\n";
317
+ echo 'Specific Post/Page Notifications take place silently behind-the-scene, using a cURL connection. Each URL will be notified every time a sale occurs.<br /><br />' . "\n";
318
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
319
  echo '<ul>' . "\n";
320
  echo '<li><code>%%sp_access_url%% = The full URL ( generated by s2Member ) where the Customer can gain access.</code></li>' . "\n";
321
  echo '<li><code>%%sp_access_exp%% = Human readable expiration for %%sp_access_url%%. Ex: <em>( link expires in %%sp_access_exp%% )</em>.</code></li>' . "\n";
322
  echo '<li><code>%%txn_id%% = The PayPal® Transaction ID. PayPal® assigns a unique identifier for every purchase.</code></li>' . "\n";
323
  echo '<li><code>%%amount%% = The full Amount of the sale. Most affiliate programs calculate commissions from this.</code></li>' . "\n";
324
+ echo '<li><code>%%first_name%% = The First Name of the Customer who purchased Specific Post/Page Access through PayPal®.</code></li>' . "\n";
325
+ echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased Specific Post/Page Access through PayPal®.</code></li>' . "\n";
326
+ echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased Specific Post/Page Access.</code></li>' . "\n";
327
+ echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased Specific Post/Page Access through PayPal®.</code></li>' . "\n";
328
+ echo '<li><code>%%item_number%% = The Item Number. Ex: <em>sp:13,24,36:72</em> ( translates to: <em>sp:comma-delimited IDs:expiration hours</em> ).</code></li>' . "\n";
329
  echo '<li><code>%%item_name%% = The Item Name. In other words, a brief description, detailing what this purchase was for.</code></li>' . "\n";
330
  echo '</ul>' . "\n";
331
  echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
333
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
334
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
335
  echo '</ul>' . "\n";
336
+ echo '<strong>This example uses cv1 to track a User\'s IP address:</strong><br />' . "\n";
337
+ echo '<em>( The IP address could be referenced in your Notification URL using %%cv1%% )</em><br />' . "\n";
338
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
339
  echo '</td>' . "\n";
340
  /**/
includes/menu-pages/buttons.inc.php CHANGED
@@ -19,7 +19,7 @@ PayPal® Button Generating page.
19
  echo '<div class="wrap ws-menu-page">' . "\n";
20
  /**/
21
  echo '<div id="icon-plugins" class="icon32"><br /></div>' . "\n";
22
- echo '<h2><div>Developed by <a href="' . ws_plugin__s2member_parse_readme_value ("Plugin URI") . '" target="_blank"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-light.png" alt="." /></a></div>s2Member / PayPal® Button Codes</h2>' . "\n";
23
  /**/
24
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
25
  /**/
@@ -50,9 +50,9 @@ if (get_option ("ws_plugin__s2member_configured") && $GLOBALS["WS_PLUGIN__"]["s2
50
  /**/
51
  echo '<td>' . "\n";
52
  echo '<form onsubmit="return false;">' . "\n";
53
- echo '<p id="ws-plugin--s2member-level1-trial-line">I\'ll offer the first <input type="text" id="ws-plugin--s2member-level1-trial-period" value="0" size="2" /> <select id="ws-plugin--s2member-level1-trial-term"><option value="D" selected="selected">Days</option><option value="W">Weeks</option><option value="M">Months</option><option value="Y">Years</option></select> free.</p>' . "\n";
54
- echo '<p><span id="ws-plugin--s2member-level1-trial-then">Then, </span>I want to charge: $<input type="text" id="ws-plugin--s2member-level1-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-level1-term"><optgroup label="Recurring Subscriptions"><option value="1-D-1">Daily ( recurring charge, for ongoing access )</option><option value="1-W-1">Weekly ( recurring charge, for ongoing access )</option><option value="1-M-1" selected="selected">Monthly ( recurring charge, for ongoing access )</option><option value="3-M-1">Quarterly ( recurring charge, for ongoing access )</option><option value="1-Y-1">Yearly ( recurring charge, for ongoing access )</option></optgroup><optgroup label="Days / Non-Recurring"><option value="1-D-0">One Time ( for 1 day access, non-recurring )</option><option value="2-D-0">One Time ( for 2 day access, non-recurring )</option><option value="3-D-0">One Time ( for 3 day access, non-recurring )</option><option value="4-D-0">One Time ( for 4 day access, non-recurring )</option><option value="5-D-0">One Time ( for 5 day access, non-recurring )</option><option value="6-D-0">One Time ( for 6 day access, non-recurring )</option></optgroup><optgroup label="Weeks / Non-Recurring"><option value="1-W-0">One Time ( for 1 week access, non-recurring )</option><option value="2-W-0">One Time ( for 2 week access, non-recurring )</option><option value="3-W-0">One Time ( for 3 week access, non-recurring )</option></optgroup><optgroup label="Months / Non-Recurring"><option value="1-M-0">One Time ( for 1 month access, non-recurring )</option><option value="2-M-0">One Time ( for 2 month access, non-recurring )</option><option value="3-M-0">One Time ( for 3 month access, non-recurring )</option><option value="4-M-0">One Time ( for 4 month access, non-recurring )</option><option value="5-M-0">One Time ( for 5 month access, non-recurring )</option><option value="6-M-0">One Time ( for 6 month access, non-recurring )</option></optgroup><optgroup label="Years / Non-Recurring"><option value="1-Y-0">One Time ( for 1 year access, non-recurring )</option><option value="2-Y-0">One Time ( for 2 year access, non-recurring )</option><option value="3-Y-0">One Time ( for 3 year access, non-recurring )</option><option value="4-Y-0">One Time ( for 4 year access, non-recurring )</option><option value="5-Y-0">One Time ( for 5 year access, non-recurring )</option></optgroup><optgroup label="Lifetime / Buy Now / Non-Recurring / No Trial"><option value="1-L-0">Buy Now ( for lifetime access, no-trial, non-recurring )</option></optgroup></select></p>' . "\n";
55
- echo '<p>Checkout Page Style <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can enter that Page Style here.\'); return false;">[?]</a>: <input type="text" id="ws-plugin--s2member-level1-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-level1-currency"><optgroup label="Currency"><option value="USD" title="U.S. Dollar">USD</option><option value="AUD" title="Australian Dollar">AUD</option><option value="BRL" title="Brazilian Real">BRL</option><option value="CAD" title="Canadian Dollar">CAD</option><option value="CZK" title="Czech Koruna">CZK</option><option value="DKK" title="Danish Krone">DKK</option><option value="EUR" title="Euro">EUR</option><option value="HKD" title="Hong Kong Dollar">HKD</option><option value="HUF" title="Hungarian Forint">HUF</option><option value="ILS" title="Israeli New Sheqel">ILS</option><option value="JPY" title="Japanese Yen">JPY</option><option value="MYR" title="Malaysian Ringgit">MYR</option><option value="MXN" title="Mexican Peso">MXN</option><option value="NOK" title="Norwegian Krone">NOK</option><option value="NZD" title="New Zealand Dollar">NZD</option><option value="PHP" title="Philippine Peso">PHP</option><option value="PLN" title="Polish Zloty">PLN</option><option value="GBP" title="Pound Sterling">GBP</option><option value="SGD" title="Singapore Dollar">SGD</option><option value="SEK" title="Swedish Krona">SEK</option><option value="CHF" title="Swiss Franc">CHF</option><option value="TWD" title="Taiwan New Dollar">TWD</option><option value="THB" title="Thai Baht">THB</option><option value="USD" title="U.S. Dollar">USD</option></optgroup></select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalButtonGenerate(\'level1\');" class="button-primary" /></p>' . "\n";
56
  echo '<p>Custom Capabilities ( comma delimited ) <a href="#" onclick="alert(\'Optional. This is VERY advanced. For full details, see:\\ns2Member -> API Scripting -> Custom Capabilities.\'); return false;">[?]</a> <input type="text" id="ws-plugin--s2member-level1-ccaps" size="40" maxlength="125" /></p>' . "\n";
57
  echo '</form>' . "\n";
58
  echo '</td>' . "\n";
@@ -112,9 +112,9 @@ if (get_option ("ws_plugin__s2member_configured") && $GLOBALS["WS_PLUGIN__"]["s2
112
  /**/
113
  echo '<td>' . "\n";
114
  echo '<form onsubmit="return false;">' . "\n";
115
- echo '<p id="ws-plugin--s2member-level2-trial-line">I\'ll offer the first <input type="text" id="ws-plugin--s2member-level2-trial-period" value="0" size="2" /> <select id="ws-plugin--s2member-level2-trial-term"><option value="D" selected="selected">Days</option><option value="W">Weeks</option><option value="M">Months</option><option value="Y">Years</option></select> free.</p>' . "\n";
116
- echo '<p><span id="ws-plugin--s2member-level2-trial-then">Then, </span>I want to charge: $<input type="text" id="ws-plugin--s2member-level2-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-level2-term"><optgroup label="Recurring Subscriptions"><option value="1-D-1">Daily ( recurring charge, for ongoing access )</option><option value="1-W-1">Weekly ( recurring charge, for ongoing access )</option><option value="1-M-1" selected="selected">Monthly ( recurring charge, for ongoing access )</option><option value="3-M-1">Quarterly ( recurring charge, for ongoing access )</option><option value="1-Y-1">Yearly ( recurring charge, for ongoing access )</option></optgroup><optgroup label="Days / Non-Recurring"><option value="1-D-0">One Time ( for 1 day access, non-recurring )</option><option value="2-D-0">One Time ( for 2 day access, non-recurring )</option><option value="3-D-0">One Time ( for 3 day access, non-recurring )</option><option value="4-D-0">One Time ( for 4 day access, non-recurring )</option><option value="5-D-0">One Time ( for 5 day access, non-recurring )</option><option value="6-D-0">One Time ( for 6 day access, non-recurring )</option></optgroup><optgroup label="Weeks / Non-Recurring"><option value="1-W-0">One Time ( for 1 week access, non-recurring )</option><option value="2-W-0">One Time ( for 2 week access, non-recurring )</option><option value="3-W-0">One Time ( for 3 week access, non-recurring )</option></optgroup><optgroup label="Months / Non-Recurring"><option value="1-M-0">One Time ( for 1 month access, non-recurring )</option><option value="2-M-0">One Time ( for 2 month access, non-recurring )</option><option value="3-M-0">One Time ( for 3 month access, non-recurring )</option><option value="4-M-0">One Time ( for 4 month access, non-recurring )</option><option value="5-M-0">One Time ( for 5 month access, non-recurring )</option><option value="6-M-0">One Time ( for 6 month access, non-recurring )</option></optgroup><optgroup label="Years / Non-Recurring"><option value="1-Y-0">One Time ( for 1 year access, non-recurring )</option><option value="2-Y-0">One Time ( for 2 year access, non-recurring )</option><option value="3-Y-0">One Time ( for 3 year access, non-recurring )</option><option value="4-Y-0">One Time ( for 4 year access, non-recurring )</option><option value="5-Y-0">One Time ( for 5 year access, non-recurring )</option></optgroup><optgroup label="Lifetime / Buy Now / Non-Recurring / No Trial"><option value="1-L-0">Buy Now ( for lifetime access, no-trial, non-recurring )</option></optgroup></select></p>' . "\n";
117
- echo '<p>Checkout Page Style <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can enter that Page Style here.\'); return false;">[?]</a>: <input type="text" id="ws-plugin--s2member-level2-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-level2-currency"><optgroup label="Currency"><option value="USD" title="U.S. Dollar">USD</option><option value="AUD" title="Australian Dollar">AUD</option><option value="BRL" title="Brazilian Real">BRL</option><option value="CAD" title="Canadian Dollar">CAD</option><option value="CZK" title="Czech Koruna">CZK</option><option value="DKK" title="Danish Krone">DKK</option><option value="EUR" title="Euro">EUR</option><option value="HKD" title="Hong Kong Dollar">HKD</option><option value="HUF" title="Hungarian Forint">HUF</option><option value="ILS" title="Israeli New Sheqel">ILS</option><option value="JPY" title="Japanese Yen">JPY</option><option value="MYR" title="Malaysian Ringgit">MYR</option><option value="MXN" title="Mexican Peso">MXN</option><option value="NOK" title="Norwegian Krone">NOK</option><option value="NZD" title="New Zealand Dollar">NZD</option><option value="PHP" title="Philippine Peso">PHP</option><option value="PLN" title="Polish Zloty">PLN</option><option value="GBP" title="Pound Sterling">GBP</option><option value="SGD" title="Singapore Dollar">SGD</option><option value="SEK" title="Swedish Krona">SEK</option><option value="CHF" title="Swiss Franc">CHF</option><option value="TWD" title="Taiwan New Dollar">TWD</option><option value="THB" title="Thai Baht">THB</option><option value="USD" title="U.S. Dollar">USD</option></optgroup></select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalButtonGenerate(\'level2\');" class="button-primary" /></p>' . "\n";
118
  echo '<p>Custom Capabilities ( comma delimited ) <a href="#" onclick="alert(\'Optional. This is VERY advanced. For full details, see:\\ns2Member -> API Scripting -> Custom Capabilities.\'); return false;">[?]</a> <input type="text" id="ws-plugin--s2member-level2-ccaps" size="40" maxlength="125" /></p>' . "\n";
119
  echo '</form>' . "\n";
120
  echo '</td>' . "\n";
@@ -174,9 +174,9 @@ if (get_option ("ws_plugin__s2member_configured") && $GLOBALS["WS_PLUGIN__"]["s2
174
  /**/
175
  echo '<td>' . "\n";
176
  echo '<form onsubmit="return false;">' . "\n";
177
- echo '<p id="ws-plugin--s2member-level3-trial-line">I\'ll offer the first <input type="text" id="ws-plugin--s2member-level3-trial-period" value="0" size="2" /> <select id="ws-plugin--s2member-level3-trial-term"><option value="D" selected="selected">Days</option><option value="W">Weeks</option><option value="M">Months</option><option value="Y">Years</option></select> free.</p>' . "\n";
178
- echo '<p><span id="ws-plugin--s2member-level3-trial-then">Then, </span>I want to charge: $<input type="text" id="ws-plugin--s2member-level3-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-level3-term"><optgroup label="Recurring Subscriptions"><option value="1-D-1">Daily ( recurring charge, for ongoing access )</option><option value="1-W-1">Weekly ( recurring charge, for ongoing access )</option><option value="1-M-1" selected="selected">Monthly ( recurring charge, for ongoing access )</option><option value="3-M-1">Quarterly ( recurring charge, for ongoing access )</option><option value="1-Y-1">Yearly ( recurring charge, for ongoing access )</option></optgroup><optgroup label="Days / Non-Recurring"><option value="1-D-0">One Time ( for 1 day access, non-recurring )</option><option value="2-D-0">One Time ( for 2 day access, non-recurring )</option><option value="3-D-0">One Time ( for 3 day access, non-recurring )</option><option value="4-D-0">One Time ( for 4 day access, non-recurring )</option><option value="5-D-0">One Time ( for 5 day access, non-recurring )</option><option value="6-D-0">One Time ( for 6 day access, non-recurring )</option></optgroup><optgroup label="Weeks / Non-Recurring"><option value="1-W-0">One Time ( for 1 week access, non-recurring )</option><option value="2-W-0">One Time ( for 2 week access, non-recurring )</option><option value="3-W-0">One Time ( for 3 week access, non-recurring )</option></optgroup><optgroup label="Months / Non-Recurring"><option value="1-M-0">One Time ( for 1 month access, non-recurring )</option><option value="2-M-0">One Time ( for 2 month access, non-recurring )</option><option value="3-M-0">One Time ( for 3 month access, non-recurring )</option><option value="4-M-0">One Time ( for 4 month access, non-recurring )</option><option value="5-M-0">One Time ( for 5 month access, non-recurring )</option><option value="6-M-0">One Time ( for 6 month access, non-recurring )</option></optgroup><optgroup label="Years / Non-Recurring"><option value="1-Y-0">One Time ( for 1 year access, non-recurring )</option><option value="2-Y-0">One Time ( for 2 year access, non-recurring )</option><option value="3-Y-0">One Time ( for 3 year access, non-recurring )</option><option value="4-Y-0">One Time ( for 4 year access, non-recurring )</option><option value="5-Y-0">One Time ( for 5 year access, non-recurring )</option></optgroup><optgroup label="Lifetime / Buy Now / Non-Recurring / No Trial"><option value="1-L-0">Buy Now ( for lifetime access, no-trial, non-recurring )</option></optgroup></select></p>' . "\n";
179
- echo '<p>Checkout Page Style <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can enter that Page Style here.\'); return false;">[?]</a>: <input type="text" id="ws-plugin--s2member-level3-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-level3-currency"><optgroup label="Currency"><option value="USD" title="U.S. Dollar">USD</option><option value="AUD" title="Australian Dollar">AUD</option><option value="BRL" title="Brazilian Real">BRL</option><option value="CAD" title="Canadian Dollar">CAD</option><option value="CZK" title="Czech Koruna">CZK</option><option value="DKK" title="Danish Krone">DKK</option><option value="EUR" title="Euro">EUR</option><option value="HKD" title="Hong Kong Dollar">HKD</option><option value="HUF" title="Hungarian Forint">HUF</option><option value="ILS" title="Israeli New Sheqel">ILS</option><option value="JPY" title="Japanese Yen">JPY</option><option value="MYR" title="Malaysian Ringgit">MYR</option><option value="MXN" title="Mexican Peso">MXN</option><option value="NOK" title="Norwegian Krone">NOK</option><option value="NZD" title="New Zealand Dollar">NZD</option><option value="PHP" title="Philippine Peso">PHP</option><option value="PLN" title="Polish Zloty">PLN</option><option value="GBP" title="Pound Sterling">GBP</option><option value="SGD" title="Singapore Dollar">SGD</option><option value="SEK" title="Swedish Krona">SEK</option><option value="CHF" title="Swiss Franc">CHF</option><option value="TWD" title="Taiwan New Dollar">TWD</option><option value="THB" title="Thai Baht">THB</option><option value="USD" title="U.S. Dollar">USD</option></optgroup></select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalButtonGenerate(\'level3\');" class="button-primary" /></p>' . "\n";
180
  echo '<p>Custom Capabilities ( comma delimited ) <a href="#" onclick="alert(\'Optional. This is VERY advanced. For full details, see:\\ns2Member -> API Scripting -> Custom Capabilities.\'); return false;">[?]</a> <input type="text" id="ws-plugin--s2member-level3-ccaps" size="40" maxlength="125" /></p>' . "\n";
181
  echo '</form>' . "\n";
182
  echo '</td>' . "\n";
@@ -236,9 +236,9 @@ if (get_option ("ws_plugin__s2member_configured") && $GLOBALS["WS_PLUGIN__"]["s2
236
  /**/
237
  echo '<td>' . "\n";
238
  echo '<form onsubmit="return false;">' . "\n";
239
- echo '<p id="ws-plugin--s2member-level4-trial-line">I\'ll offer the first <input type="text" id="ws-plugin--s2member-level4-trial-period" value="0" size="2" /> <select id="ws-plugin--s2member-level4-trial-term"><option value="D" selected="selected">Days</option><option value="W">Weeks</option><option value="M">Months</option><option value="Y">Years</option></select> free.</p>' . "\n";
240
- echo '<p><span id="ws-plugin--s2member-level4-trial-then">Then, </span>I want to charge: $<input type="text" id="ws-plugin--s2member-level4-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-level4-term"><optgroup label="Recurring Subscriptions"><option value="1-D-1">Daily ( recurring charge, for ongoing access )</option><option value="1-W-1">Weekly ( recurring charge, for ongoing access )</option><option value="1-M-1" selected="selected">Monthly ( recurring charge, for ongoing access )</option><option value="3-M-1">Quarterly ( recurring charge, for ongoing access )</option><option value="1-Y-1">Yearly ( recurring charge, for ongoing access )</option></optgroup><optgroup label="Days / Non-Recurring"><option value="1-D-0">One Time ( for 1 day access, non-recurring )</option><option value="2-D-0">One Time ( for 2 day access, non-recurring )</option><option value="3-D-0">One Time ( for 3 day access, non-recurring )</option><option value="4-D-0">One Time ( for 4 day access, non-recurring )</option><option value="5-D-0">One Time ( for 5 day access, non-recurring )</option><option value="6-D-0">One Time ( for 6 day access, non-recurring )</option></optgroup><optgroup label="Weeks / Non-Recurring"><option value="1-W-0">One Time ( for 1 week access, non-recurring )</option><option value="2-W-0">One Time ( for 2 week access, non-recurring )</option><option value="3-W-0">One Time ( for 3 week access, non-recurring )</option></optgroup><optgroup label="Months / Non-Recurring"><option value="1-M-0">One Time ( for 1 month access, non-recurring )</option><option value="2-M-0">One Time ( for 2 month access, non-recurring )</option><option value="3-M-0">One Time ( for 3 month access, non-recurring )</option><option value="4-M-0">One Time ( for 4 month access, non-recurring )</option><option value="5-M-0">One Time ( for 5 month access, non-recurring )</option><option value="6-M-0">One Time ( for 6 month access, non-recurring )</option></optgroup><optgroup label="Years / Non-Recurring"><option value="1-Y-0">One Time ( for 1 year access, non-recurring )</option><option value="2-Y-0">One Time ( for 2 year access, non-recurring )</option><option value="3-Y-0">One Time ( for 3 year access, non-recurring )</option><option value="4-Y-0">One Time ( for 4 year access, non-recurring )</option><option value="5-Y-0">One Time ( for 5 year access, non-recurring )</option></optgroup><optgroup label="Lifetime / Buy Now / Non-Recurring / No Trial"><option value="1-L-0">Buy Now ( for lifetime access, no-trial, non-recurring )</option></optgroup></select></p>' . "\n";
241
- echo '<p>Checkout Page Style <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can enter that Page Style here.\'); return false;">[?]</a>: <input type="text" id="ws-plugin--s2member-level4-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-level4-currency"><optgroup label="Currency"><option value="USD" title="U.S. Dollar">USD</option><option value="AUD" title="Australian Dollar">AUD</option><option value="BRL" title="Brazilian Real">BRL</option><option value="CAD" title="Canadian Dollar">CAD</option><option value="CZK" title="Czech Koruna">CZK</option><option value="DKK" title="Danish Krone">DKK</option><option value="EUR" title="Euro">EUR</option><option value="HKD" title="Hong Kong Dollar">HKD</option><option value="HUF" title="Hungarian Forint">HUF</option><option value="ILS" title="Israeli New Sheqel">ILS</option><option value="JPY" title="Japanese Yen">JPY</option><option value="MYR" title="Malaysian Ringgit">MYR</option><option value="MXN" title="Mexican Peso">MXN</option><option value="NOK" title="Norwegian Krone">NOK</option><option value="NZD" title="New Zealand Dollar">NZD</option><option value="PHP" title="Philippine Peso">PHP</option><option value="PLN" title="Polish Zloty">PLN</option><option value="GBP" title="Pound Sterling">GBP</option><option value="SGD" title="Singapore Dollar">SGD</option><option value="SEK" title="Swedish Krona">SEK</option><option value="CHF" title="Swiss Franc">CHF</option><option value="TWD" title="Taiwan New Dollar">TWD</option><option value="THB" title="Thai Baht">THB</option><option value="USD" title="U.S. Dollar">USD</option></optgroup></select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalButtonGenerate(\'level4\');" class="button-primary" /></p>' . "\n";
242
  echo '<p>Custom Capabilities ( comma delimited ) <a href="#" onclick="alert(\'Optional. This is VERY advanced. For full details, see:\\ns2Member -> API Scripting -> Custom Capabilities.\'); return false;">[?]</a> <input type="text" id="ws-plugin--s2member-level4-ccaps" size="40" maxlength="125" /></p>' . "\n";
243
  echo '</form>' . "\n";
244
  echo '</td>' . "\n";
@@ -284,7 +284,7 @@ if (get_option ("ws_plugin__s2member_configured") && $GLOBALS["WS_PLUGIN__"]["s2
284
  echo '<h3>Button Code Generator For Subscription Modifications</h3>' . "\n";
285
  echo '<p>If you\'d like to give your Members ( and/or your Free Subscribers ) the ability to modify their billing plan, by switching to a more expensive option, or a less expensive option; generate a new PayPal® Modification Button here. Configure the updated Level, pricing, terms, etc. Then, make that new Modification Button available to Members who are logged into their existing account with you. For example, you might want to insert a "Level #2" Upgrade Button into your Login Welcome Page, which would up-sell existing Level #1 Members to a more expensive plan that you offer.</p>' . "\n";
286
  echo '<p><em><strong>*Modification Process*</strong> When you send a Member to PayPal® using a Subscription Modification Button, PayPal® will ask them to login. Once they\'re logged in, instead of being able to signup for a new membership, PayPal® will provide them with the ability to upgrade and/or downgrade their existing membership with you, by allowing them to switch to the Membership Plan that was specified in the Subscription Modification Button. PayPal® handles this nicely, and you\'ll be happy to know that s2Member has been pre-configured to deal with this scenario as well, so that everything remains automated. Their Membership Access Level will either be promoted, or demoted, based on the actions they took at PayPal® during the modification process. Once an existing Member completes their Subscription Modification at PayPal®, they\'ll be brought back to their Login Welcome Page, instead of the registration screen.</em></p>' . "\n";
287
- echo '<p><em><strong>*Also Works For Free Subscribers*</strong> Although a Free Subscriber does not have an existing PayPal® subscription, s2Member is capable of adapting to this scenario gracefully. Just make sure that your existing Free Subscribers ( the ones who wish to upgrade ) pay for their Membership through a Modification Button generated by s2Member. That will allow them to continue using their existing account with you. In other words, they can keep their existing Username ( and anything already associated with that Username ), rather than being forced to re-register after checkout.</em></p>' . "\n";
288
  echo '<p><em><strong>*Make It More User-Friendly*</strong> You can make the Subscription Modification Process, more user-friendly, by setting up a <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can tell s2Member to use that Page Style whenever you generate your Button Code.\'); return false;">Custom Page Style at PayPal®</a>, specifically for Subscription Modification Buttons. Use a custom header image, with a brief explanation to the Customer. Something like, "Log into PayPal®", "You can Modify your Subscription!".</em></p>' . "\n";
289
  echo '<p><em>* Buttons are NOT saved here. This is only a Button Generator. Once you\'ve generated your Button, copy/paste it into your Login Welcome Page, or wherever you feel it would be most appropriate. If you lose your Button Code, you\'ll need to come back &amp; re-generate a new one. If you\'re in Sandbox Test-Mode, and you\'re NOT using the Shortcode Format, please remember to come back and re-generate your Buttons before you go live.</em></p>' . "\n";
290
  /**/
@@ -301,10 +301,10 @@ if (get_option ("ws_plugin__s2member_configured") && $GLOBALS["WS_PLUGIN__"]["s2
301
  /**/
302
  echo '<td>' . "\n";
303
  echo '<form onsubmit="return false;">' . "\n";
304
- echo '<p>Modification: <select id="ws-plugin--s2member-modification-level"><optgroup label="Level #1"><option value="upgrade:1">&uarr; Upgrade To Level #1</option><option value="downgrade:1">&darr; Downgrade To Level #1</option></optgroup><optgroup label="Level #2"><option value="upgrade:2" selected="selected">&uarr; Upgrade To Level #2</option><option value="downgrade:2">&darr; Downgrade To Level #2</option></optgroup><optgroup label="Level #3"><option value="upgrade:3">&uarr; Upgrade To Level #3</option><option value="downgrade:3">&darr; Downgrade To Level #3</option></optgroup><optgroup label="Level #4"><option value="upgrade:4">&uarr; Upgrade To Level #4</option></optgroup></select></p>' . "\n";
305
- echo '<p id="ws-plugin--s2member-modification-trial-line">I\'ll offer the first <input type="text" id="ws-plugin--s2member-modification-trial-period" value="0" size="2" /> <select id="ws-plugin--s2member-modification-trial-term"><option value="D" selected="selected">Days</option><option value="W">Weeks</option><option value="M">Months</option><option value="Y">Years</option></select> free.</p>' . "\n";
306
- echo '<p><span id="ws-plugin--s2member-modification-trial-then">Then, </span>I want to charge: $<input type="text" id="ws-plugin--s2member-modification-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-modification-term"><optgroup label="Recurring Subscriptions"><option value="1-D-1">Daily ( recurring charge, for ongoing access )</option><option value="1-W-1">Weekly ( recurring charge, for ongoing access )</option><option value="1-M-1" selected="selected">Monthly ( recurring charge, for ongoing access )</option><option value="3-M-1">Quarterly ( recurring charge, for ongoing access )</option><option value="1-Y-1">Yearly ( recurring charge, for ongoing access )</option></optgroup><optgroup label="Days / Non-Recurring"><option value="1-D-0">One Time ( for 1 day access, non-recurring )</option><option value="2-D-0">One Time ( for 2 day access, non-recurring )</option><option value="3-D-0">One Time ( for 3 day access, non-recurring )</option><option value="4-D-0">One Time ( for 4 day access, non-recurring )</option><option value="5-D-0">One Time ( for 5 day access, non-recurring )</option><option value="6-D-0">One Time ( for 6 day access, non-recurring )</option></optgroup><optgroup label="Weeks / Non-Recurring"><option value="1-W-0">One Time ( for 1 week access, non-recurring )</option><option value="2-W-0">One Time ( for 2 week access, non-recurring )</option><option value="3-W-0">One Time ( for 3 week access, non-recurring )</option></optgroup><optgroup label="Months / Non-Recurring"><option value="1-M-0">One Time ( for 1 month access, non-recurring )</option><option value="2-M-0">One Time ( for 2 month access, non-recurring )</option><option value="3-M-0">One Time ( for 3 month access, non-recurring )</option><option value="4-M-0">One Time ( for 4 month access, non-recurring )</option><option value="5-M-0">One Time ( for 5 month access, non-recurring )</option><option value="6-M-0">One Time ( for 6 month access, non-recurring )</option></optgroup><optgroup label="Years / Non-Recurring"><option value="1-Y-0">One Time ( for 1 year access, non-recurring )</option><option value="2-Y-0">One Time ( for 2 year access, non-recurring )</option><option value="3-Y-0">One Time ( for 3 year access, non-recurring )</option><option value="4-Y-0">One Time ( for 4 year access, non-recurring )</option><option value="5-Y-0">One Time ( for 5 year access, non-recurring )</option></optgroup><optgroup label="Lifetime / Buy Now / Non-Recurring / No Trial"><option value="1-L-0">Buy Now ( for lifetime access, no-trial, non-recurring )</option></optgroup></select><br /><small>** Watch out for <a href="https://www.x.com/thread/41748" target="_blank" rel="external">the 20% rule</a>. Additional details on the 20% rule are <a href="https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_WPRecurringPayments#id086530108PM__id08653060UE6" target="_blank" rel="external">documented here</a>.</small></p>' . "\n";
307
- echo '<p>Checkout Page Style <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can enter that Page Style here.\'); return false;">[?]</a>: <input type="text" id="ws-plugin--s2member-modification-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-modification-currency"><optgroup label="Currency"><option value="USD" title="U.S. Dollar">USD</option><option value="AUD" title="Australian Dollar">AUD</option><option value="BRL" title="Brazilian Real">BRL</option><option value="CAD" title="Canadian Dollar">CAD</option><option value="CZK" title="Czech Koruna">CZK</option><option value="DKK" title="Danish Krone">DKK</option><option value="EUR" title="Euro">EUR</option><option value="HKD" title="Hong Kong Dollar">HKD</option><option value="HUF" title="Hungarian Forint">HUF</option><option value="ILS" title="Israeli New Sheqel">ILS</option><option value="JPY" title="Japanese Yen">JPY</option><option value="MYR" title="Malaysian Ringgit">MYR</option><option value="MXN" title="Mexican Peso">MXN</option><option value="NOK" title="Norwegian Krone">NOK</option><option value="NZD" title="New Zealand Dollar">NZD</option><option value="PHP" title="Philippine Peso">PHP</option><option value="PLN" title="Polish Zloty">PLN</option><option value="GBP" title="Pound Sterling">GBP</option><option value="SGD" title="Singapore Dollar">SGD</option><option value="SEK" title="Swedish Krona">SEK</option><option value="CHF" title="Swiss Franc">CHF</option><option value="TWD" title="Taiwan New Dollar">TWD</option><option value="THB" title="Thai Baht">THB</option><option value="USD" title="U.S. Dollar">USD</option></optgroup></select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalButtonGenerate(\'modification\');" class="button-primary" /></p>' . "\n";
308
  echo '<p>Custom Capabilities ( comma delimited ) <a href="#" onclick="alert(\'Optional. This is VERY advanced. For full details, see:\\ns2Member -> API Scripting -> Custom Capabilities.\'); return false;">[?]</a> <input type="text" id="ws-plugin--s2member-modification-ccaps" size="40" maxlength="125" /></p>' . "\n";
309
  echo '</form>' . "\n";
310
  echo '</td>' . "\n";
@@ -350,8 +350,8 @@ if (get_option ("ws_plugin__s2member_configured") && $GLOBALS["WS_PLUGIN__"]["s2
350
  /**/
351
  echo '<div class="ws-menu-page-section ws-plugin--s2member-cancellation-section">' . "\n";
352
  echo '<h3>One Button Does It All For Cancellations ( copy/paste )</h3>' . "\n";
353
- echo '<p>Since every paid Membership is associated with a PayPal® Subscription; and every PayPal® Subscription is associated with a PayPal® Account; your Members will always have a PayPal® Account of their own, which is tied to their Membership with you. So... a Member can simply log into their own PayPal® account and cancel their subscription(s) with you at anytime, all on their own. However, some Customers do not realize this. So, if you would like to make it clearer ( easier ) for Members to cancel their own subscription(s), you can provide this Cancellation Button for them on your Login Welcome Page, or somewhere in the support section of your website. Note... you don\'t have to use this Cancellation Button at all, if you don\'t want to. It\'s completely optional.</p>' . "\n";
354
- echo '<p><em><strong>*Cancellation Process*</strong> Very simple. A Member clicks the Cancellation Button. PayPal® asks them to log into their PayPal® account. Once they\'re logged in, PayPal® will display a list of all active subscriptions they have with you. They choose which ones they want to cancel, and s2Member is notified silently behind-the-scene, through the PayPal® IPN service.</em></p>' . "\n";
355
  /**/
356
  echo '<table class="form-table">' . "\n";
357
  echo '<tbody>' . "\n";
@@ -401,13 +401,14 @@ if (get_option ("ws_plugin__s2member_configured") && $GLOBALS["WS_PLUGIN__"]["s2
401
  /**/
402
  echo '</div>' . "\n";
403
  /**/
404
- echo '<div class="ws-menu-page-group" title="PayPal® Single-Page &quot;Buy Now&quot; Access">' . "\n";
405
  /**/
406
- echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-section">' . "\n";
407
- echo '<h3>Button Code Generator For Single-Page Buy Now Buttons</h3>' . "\n";
408
- echo '<p>s2Member now supports an additional layer of functionality ( very powerful ), which allows you to sell access to specific Pages that you\'ve created in WordPress®. Single-Page Access works independently from Member Level Access. That is, you can sell an unlimited number of Pages using "Buy Now" Buttons, and your Customers will NOT be required to have a Membership Account with your site in order to receive access. If they are already a Member, that\'s fine, but they won\'t need to be. In other words, Customers will NOT need to login, just to receive access to the Single-Page they purchased access to. s2Member will immediately redirect the Customer to the Single-Page after checkout is completed successfully. An email is also sent to the Customer with a link ( see: <code>s2Member -> PayPal® Options -> Single-Page Email</code> ). Authentication is handled automatically through self-expiring links, good for 72 hours by default.</p>' . "\n";
409
- echo '<p>Single-Page Access, is sort of like selling a product. Only, instead of shipping anything to the Customer, you just give them access to a specific Page on your site; one that you created in WordPress®. A Single-Page that is protected by s2Member, might contain a download link for your eBook, access to file &amp; music downloads, access to additional support services, and the list goes on and on. The possibilities with this are endless; as long as your digital product can be delivered through access to a WordPress® Page that you\'ve created. To protect Single-Pages, please see: <code>s2Member -> General Options -> Single-Page Access Restrictions</code>. Once you\'ve configured your Single-Page Restrictions, those Pages will be available in the drop-down menu below.</p>' . "\n";
410
- echo '<p>Very simple. All you do is customize the form fields provided, for each Page that you plan to sell. Then press (Generate Button Code). These special PayPal® Buttons are customized to work with s2Member seamlessly.</p>' . "\n";
 
411
  echo '<p><em>* Buttons are NOT saved here. This is only a Button Generator. Once you\'ve generated your Button, copy/paste it into your WordPress® Editor, wherever you feel it would be most appropriate. If you lose your Button Code, you\'ll need to come back &amp; re-generate a new one. If you\'re in Sandbox Test-Mode, and you\'re NOT using the Shortcode Format, please remember to come back and re-generate your Buttons before you go live.</em></p>' . "\n";
412
  /**/
413
  echo '<table class="form-table">' . "\n";
@@ -416,20 +417,33 @@ if (get_option ("ws_plugin__s2member_configured") && $GLOBALS["WS_PLUGIN__"]["s2
416
  /**/
417
  echo '<th class="ws-menu-page-th-side">' . "\n";
418
  echo '<label for="ws-plugin--s2member-sp-shortcode">' . "\n";
419
- echo 'Button Code<br />Single-Page Access:<br /><br />' . "\n";
420
  echo '<div id="ws-plugin--s2member-sp-button-prev"></div>' . "\n";
421
  echo '</label>' . "\n";
422
  echo '</th>' . "\n";
423
  /**/
424
  echo '<td>' . "\n";
425
  echo '<form onsubmit="return false;">' . "\n";
426
- echo '<p><select id="ws-plugin--s2member-sp-page">' . "\n";
427
- echo '<option value="">&mdash; Select A Protected Single-Page &mdash;</option>' . "\n";
 
 
 
 
 
 
 
 
 
 
 
 
428
  /**/
429
- $ws_plugin__s2member_temp_s_pages = ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["single_pages"]) ?/**/
430
- array_merge ((array)get_pages ("include=" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["single_pages"])) : array ();
431
  /**/
432
- foreach (($ws_plugin__s2member_temp_a = $ws_plugin__s2member_temp_s_pages) as $ws_plugin__s2member_temp_o)
 
 
433
  if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"])
434
  if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
435
  if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_limit_exceeded_page"])
@@ -439,10 +453,11 @@ if (get_option ("ws_plugin__s2member_configured") && $GLOBALS["WS_PLUGIN__"]["s2
439
  if (!in_array ($ws_plugin__s2member_temp_o->ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_pages"])))
440
  echo '<option value="' . esc_attr ($ws_plugin__s2member_temp_o->ID) . '">' . esc_html ($ws_plugin__s2member_temp_o->post_title) . '</option>' . "\n";
441
  /**/
442
- echo '</select></p>' . "\n";
 
443
  echo '<p>Description: <input type="text" id="ws-plugin--s2member-sp-desc" value="" size="68" /></p>' . "\n";
444
- echo '<p>I want to charge: $<input type="text" id="ws-plugin--s2member-sp-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-sp-hours"><optgroup label="Expires In Hours"><option value="2">Buy Now ( Single-Page Link, valid for 2 hours )</option><option value="4">Buy Now ( Single-Page Link, valid for 4 hours )</option><option value="6">Buy Now ( Single-Page Link, valid for 6 hours )</option><option value="8">Buy Now ( Single-Page Link, valid for 8 hours )</option><option value="10">Buy Now ( Single-Page Link, valid for 10 hours )</option><option value="12">Buy Now ( Single-Page Link, valid for 12 hours )</option></optgroup><optgroup label="Expires In Days"><option value="24">Buy Now ( Single-Page Link, valid for 1 day )</option><option value="48">Buy Now ( Single-Page Link, valid for 2 days )</option><option value="72" selected="selected">Buy Now ( Single-Page Link, valid for 3 days )</option><option value="96">Buy Now ( Single-Page Link, valid for 4 days )</option><option value="120">Buy Now ( Single-Page Link, valid for 5 days )</option><option value="144">Buy Now ( Single-Page Link, valid for 6 days )</option></optgroup><optgroup label="Expires In Weeks"><option value="168">Buy Now ( Single-Page Link, valid for 1 week )</option><option value="336">Buy Now ( Single-Page Link, valid for 2 weeks )</option><option value="504">Buy Now ( Single-Page Link, valid for 3 weeks )</option></optgroup><optgroup label="Expires In Months"><option value="720">Buy Now ( Single-Page Link, valid for 1 month )</option><option value="1440">Buy Now ( Single-Page Link, valid for 2 months )</option><option value="2190">Buy Now ( Single-Page Link, valid for 3 months )</option><option value="4380">Buy Now ( Single-Page Link, valid for 6 months )</option></optgroup><optgroup label="Expires In Years"><option value="8760">Buy Now ( Single-Page Link, valid for 1 year )</option><option value="17520">Buy Now ( Single-Page Link, valid for 2 years )</option><option value="26280">Buy Now ( Single-Page Link, valid for 3 years )</option><option value="35040">Buy Now ( Single-Page Link, valid for 4 years )</option><option value="43800">Buy Now ( Single-Page Link, valid for 5 years )</option></optgroup></select></p>' . "\n";
445
- echo '<p>Checkout Page Style <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can enter that Page Style here.\'); return false;">[?]</a>: <input type="text" id="ws-plugin--s2member-sp-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-sp-currency"><optgroup label="Currency"><option value="USD" title="U.S. Dollar">USD</option><option value="AUD" title="Australian Dollar">AUD</option><option value="BRL" title="Brazilian Real">BRL</option><option value="CAD" title="Canadian Dollar">CAD</option><option value="CZK" title="Czech Koruna">CZK</option><option value="DKK" title="Danish Krone">DKK</option><option value="EUR" title="Euro">EUR</option><option value="HKD" title="Hong Kong Dollar">HKD</option><option value="HUF" title="Hungarian Forint">HUF</option><option value="ILS" title="Israeli New Sheqel">ILS</option><option value="JPY" title="Japanese Yen">JPY</option><option value="MYR" title="Malaysian Ringgit">MYR</option><option value="MXN" title="Mexican Peso">MXN</option><option value="NOK" title="Norwegian Krone">NOK</option><option value="NZD" title="New Zealand Dollar">NZD</option><option value="PHP" title="Philippine Peso">PHP</option><option value="PLN" title="Polish Zloty">PLN</option><option value="GBP" title="Pound Sterling">GBP</option><option value="SGD" title="Singapore Dollar">SGD</option><option value="SEK" title="Swedish Krona">SEK</option><option value="CHF" title="Swiss Franc">CHF</option><option value="TWD" title="Taiwan New Dollar">TWD</option><option value="THB" title="Thai Baht">THB</option><option value="USD" title="U.S. Dollar">USD</option></optgroup></select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalSpButtonGenerate();" class="button-primary" /></p>' . "\n";
446
  echo '</form>' . "\n";
447
  echo '</td>' . "\n";
448
  /**/
@@ -473,11 +488,15 @@ if (get_option ("ws_plugin__s2member_configured") && $GLOBALS["WS_PLUGIN__"]["s2
473
  echo '</tr>' . "\n";
474
  echo '</tbody>' . "\n";
475
  echo '</table>' . "\n";
 
476
  /**/
477
- echo '<div class="ws-menu-page-hr"></div>' . "\n";
478
  /**/
479
- echo '<h3>Single-Page Link Generator ( for Customer Service )</h3>' . "\n";
480
- echo '<p>s2Member automatically generates Single-Page Links for your Customers after checkout, and also sends them a link in a Confirmation Email. However, if you ever need to deal with a Customer Service issue that requires a new Single-Page Link to be created, you can use this tool for that.</p>' . "\n";
 
 
 
481
  /**/
482
  echo '<table class="form-table">' . "\n";
483
  echo '<tbody>' . "\n";
@@ -485,10 +504,23 @@ if (get_option ("ws_plugin__s2member_configured") && $GLOBALS["WS_PLUGIN__"]["s2
485
  /**/
486
  echo '<td>' . "\n";
487
  echo '<form onsubmit="return false;">' . "\n";
488
- echo '<p><select id="ws-plugin--s2member-sp-link-page">' . "\n";
489
- echo '<option value="">&mdash; Select A Protected Single-Page &mdash;</option>' . "\n";
 
 
 
 
 
 
 
 
 
 
 
490
  /**/
491
- foreach (($ws_plugin__s2member_temp_a = $ws_plugin__s2member_temp_s_pages) as $ws_plugin__s2member_temp_o)
 
 
492
  if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"])
493
  if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
494
  if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_limit_exceeded_page"])
@@ -498,8 +530,9 @@ if (get_option ("ws_plugin__s2member_configured") && $GLOBALS["WS_PLUGIN__"]["s2
498
  if (!in_array ($ws_plugin__s2member_temp_o->ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_pages"])))
499
  echo '<option value="' . esc_attr ($ws_plugin__s2member_temp_o->ID) . '">' . esc_html ($ws_plugin__s2member_temp_o->post_title) . '</option>' . "\n";
500
  /**/
501
- echo '</select> <select id="ws-plugin--s2member-sp-link-hours"><optgroup label="Hours"><option value="2">valid for 2 hours</option><option value="4">valid for 4 hours</option><option value="6">valid for 6 hours</option><option value="8">valid for 8 hours</option><option value="10">valid for 10 hours</option><option value="12">valid for 12 hours</option></optgroup><optgroup label="Days"><option value="24">valid for 1 day</option><option value="48">valid for 2 days</option><option value="72" selected="selected">valid for 3 days</option><option value="96">valid for 4 days</option><option value="120">valid for 5 days</option><option value="144">valid for 6 days</option></optgroup><optgroup label="Weeks"><option value="168">valid for 1 week</option><option value="336">valid for 2 weeks</option><option value="504">valid for 3 weeks</option></optgroup><optgroup label="Months"><option value="720">valid for 1 month</option><option value="1440">valid for 2 months</option><option value="2190">valid for 3 months</option><option value="4380">valid for 6 months</option></optgroup><optgroup label="Years"><option value="8760">valid for 1 year</option><option value="17520">valid for 2 years</option><option value="26280">valid for 3 years</option><option value="35040">valid for 4 years</option><option value="43800">valid for 5 years</option></optgroup></select> <input type="button" value="Generate Link" onclick="ws_plugin__s2member_paypalSpLinkGenerate();" class="button-primary" /> <img id="ws-plugin--s2member-sp-link-loading" src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/ajax-loader.gif" alt="" style="display:none;" /></p>' . "\n";
502
  /**/
 
503
  echo '<p id="ws-plugin--s2member-sp-link" style="font-family:Consolas, monospace; display:none;"></p>' . "\n";
504
  echo '</form>' . "\n";
505
  echo '</td>' . "\n";
19
  echo '<div class="wrap ws-menu-page">' . "\n";
20
  /**/
21
  echo '<div id="icon-plugins" class="icon32"><br /></div>' . "\n";
22
+ echo '<h2><div>Developed by <a href="' . ws_plugin__s2member_parse_readme_value ("Plugin URI") . '" target="_blank"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-light.png" alt="." /></a></div>s2Member / PayPal® Buttons</h2>' . "\n";
23
  /**/
24
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
25
  /**/
50
  /**/
51
  echo '<td>' . "\n";
52
  echo '<form onsubmit="return false;">' . "\n";
53
+ echo '<p id="ws-plugin--s2member-level1-trial-line">I\'ll offer the first <input type="text" id="ws-plugin--s2member-level1-trial-period" value="0" size="2" /> <select id="ws-plugin--s2member-level1-trial-term">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/membership-trial-terms.html") . '</select> free.</p>' . "\n";
54
+ echo '<p><span id="ws-plugin--s2member-level1-trial-then">Then, </span>I want to charge: $<input type="text" id="ws-plugin--s2member-level1-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-level1-term">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/membership-regular-terms.html") . '</select></p>' . "\n";
55
+ echo '<p>Checkout Page Style <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can enter that Page Style here.\\n\\nIn addition. The Shortcode below, provided by s2Member; supports an image attribute: image=\\\'\\\'default\\\'\\\'. This can be changed to a full URL, pointing to a custom image of your own; instead of the default PayPal® Button image.\'); return false;">[?]</a>: <input type="text" id="ws-plugin--s2member-level1-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-level1-currency">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/currencies.html") . '</select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalButtonGenerate(\'level1\');" class="button-primary" /></p>' . "\n";
56
  echo '<p>Custom Capabilities ( comma delimited ) <a href="#" onclick="alert(\'Optional. This is VERY advanced. For full details, see:\\ns2Member -> API Scripting -> Custom Capabilities.\'); return false;">[?]</a> <input type="text" id="ws-plugin--s2member-level1-ccaps" size="40" maxlength="125" /></p>' . "\n";
57
  echo '</form>' . "\n";
58
  echo '</td>' . "\n";
112
  /**/
113
  echo '<td>' . "\n";
114
  echo '<form onsubmit="return false;">' . "\n";
115
+ echo '<p id="ws-plugin--s2member-level2-trial-line">I\'ll offer the first <input type="text" id="ws-plugin--s2member-level2-trial-period" value="0" size="2" /> <select id="ws-plugin--s2member-level2-trial-term">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/membership-trial-terms.html") . '</select> free.</p>' . "\n";
116
+ echo '<p><span id="ws-plugin--s2member-level2-trial-then">Then, </span>I want to charge: $<input type="text" id="ws-plugin--s2member-level2-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-level2-term">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/membership-regular-terms.html") . '</select></p>' . "\n";
117
+ echo '<p>Checkout Page Style <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can enter that Page Style here.\\n\\nIn addition. The Shortcode below, provided by s2Member; supports an image attribute: image=\\\'\\\'default\\\'\\\'. This can be changed to a full URL, pointing to a custom image of your own; instead of the default PayPal® Button image.\'); return false;">[?]</a>: <input type="text" id="ws-plugin--s2member-level2-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-level2-currency">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/currencies.html") . '</select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalButtonGenerate(\'level2\');" class="button-primary" /></p>' . "\n";
118
  echo '<p>Custom Capabilities ( comma delimited ) <a href="#" onclick="alert(\'Optional. This is VERY advanced. For full details, see:\\ns2Member -> API Scripting -> Custom Capabilities.\'); return false;">[?]</a> <input type="text" id="ws-plugin--s2member-level2-ccaps" size="40" maxlength="125" /></p>' . "\n";
119
  echo '</form>' . "\n";
120
  echo '</td>' . "\n";
174
  /**/
175
  echo '<td>' . "\n";
176
  echo '<form onsubmit="return false;">' . "\n";
177
+ echo '<p id="ws-plugin--s2member-level3-trial-line">I\'ll offer the first <input type="text" id="ws-plugin--s2member-level3-trial-period" value="0" size="2" /> <select id="ws-plugin--s2member-level3-trial-term">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/membership-trial-terms.html") . '</select> free.</p>' . "\n";
178
+ echo '<p><span id="ws-plugin--s2member-level3-trial-then">Then, </span>I want to charge: $<input type="text" id="ws-plugin--s2member-level3-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-level3-term">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/membership-regular-terms.html") . '</select></p>' . "\n";
179
+ echo '<p>Checkout Page Style <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can enter that Page Style here.\\n\\nIn addition. The Shortcode below, provided by s2Member; supports an image attribute: image=\\\'\\\'default\\\'\\\'. This can be changed to a full URL, pointing to a custom image of your own; instead of the default PayPal® Button image.\'); return false;">[?]</a>: <input type="text" id="ws-plugin--s2member-level3-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-level3-currency">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/currencies.html") . '</select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalButtonGenerate(\'level3\');" class="button-primary" /></p>' . "\n";
180
  echo '<p>Custom Capabilities ( comma delimited ) <a href="#" onclick="alert(\'Optional. This is VERY advanced. For full details, see:\\ns2Member -> API Scripting -> Custom Capabilities.\'); return false;">[?]</a> <input type="text" id="ws-plugin--s2member-level3-ccaps" size="40" maxlength="125" /></p>' . "\n";
181
  echo '</form>' . "\n";
182
  echo '</td>' . "\n";
236
  /**/
237
  echo '<td>' . "\n";
238
  echo '<form onsubmit="return false;">' . "\n";
239
+ echo '<p id="ws-plugin--s2member-level4-trial-line">I\'ll offer the first <input type="text" id="ws-plugin--s2member-level4-trial-period" value="0" size="2" /> <select id="ws-plugin--s2member-level4-trial-term">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/membership-trial-terms.html") . '</select> free.</p>' . "\n";
240
+ echo '<p><span id="ws-plugin--s2member-level4-trial-then">Then, </span>I want to charge: $<input type="text" id="ws-plugin--s2member-level4-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-level4-term">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/membership-regular-terms.html") . '</select></p>' . "\n";
241
+ echo '<p>Checkout Page Style <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can enter that Page Style here.\\n\\nIn addition. The Shortcode below, provided by s2Member; supports an image attribute: image=\\\'\\\'default\\\'\\\'. This can be changed to a full URL, pointing to a custom image of your own; instead of the default PayPal® Button image.\'); return false;">[?]</a>: <input type="text" id="ws-plugin--s2member-level4-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-level4-currency">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/currencies.html") . '</select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalButtonGenerate(\'level4\');" class="button-primary" /></p>' . "\n";
242
  echo '<p>Custom Capabilities ( comma delimited ) <a href="#" onclick="alert(\'Optional. This is VERY advanced. For full details, see:\\ns2Member -> API Scripting -> Custom Capabilities.\'); return false;">[?]</a> <input type="text" id="ws-plugin--s2member-level4-ccaps" size="40" maxlength="125" /></p>' . "\n";
243
  echo '</form>' . "\n";
244
  echo '</td>' . "\n";
284
  echo '<h3>Button Code Generator For Subscription Modifications</h3>' . "\n";
285
  echo '<p>If you\'d like to give your Members ( and/or your Free Subscribers ) the ability to modify their billing plan, by switching to a more expensive option, or a less expensive option; generate a new PayPal® Modification Button here. Configure the updated Level, pricing, terms, etc. Then, make that new Modification Button available to Members who are logged into their existing account with you. For example, you might want to insert a "Level #2" Upgrade Button into your Login Welcome Page, which would up-sell existing Level #1 Members to a more expensive plan that you offer.</p>' . "\n";
286
  echo '<p><em><strong>*Modification Process*</strong> When you send a Member to PayPal® using a Subscription Modification Button, PayPal® will ask them to login. Once they\'re logged in, instead of being able to signup for a new membership, PayPal® will provide them with the ability to upgrade and/or downgrade their existing membership with you, by allowing them to switch to the Membership Plan that was specified in the Subscription Modification Button. PayPal® handles this nicely, and you\'ll be happy to know that s2Member has been pre-configured to deal with this scenario as well, so that everything remains automated. Their Membership Access Level will either be promoted, or demoted, based on the actions they took at PayPal® during the modification process. Once an existing Member completes their Subscription Modification at PayPal®, they\'ll be brought back to their Login Welcome Page, instead of the registration screen.</em></p>' . "\n";
287
+ echo '<p><em><strong>*Also Works For Free Subscribers*</strong> Although a Free Subscriber does not have an existing PayPal® Subscription, s2Member is capable of adapting to this scenario gracefully. Just make sure that your existing Free Subscribers ( the ones who wish to upgrade ) pay for their Membership through a Modification Button generated by s2Member. That will allow them to continue using their existing account with you. In other words, they can keep their existing Username ( and anything already associated with that Username ), rather than being forced to re-register after checkout.</em></p>' . "\n";
288
  echo '<p><em><strong>*Make It More User-Friendly*</strong> You can make the Subscription Modification Process, more user-friendly, by setting up a <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can tell s2Member to use that Page Style whenever you generate your Button Code.\'); return false;">Custom Page Style at PayPal®</a>, specifically for Subscription Modification Buttons. Use a custom header image, with a brief explanation to the Customer. Something like, "Log into PayPal®", "You can Modify your Subscription!".</em></p>' . "\n";
289
  echo '<p><em>* Buttons are NOT saved here. This is only a Button Generator. Once you\'ve generated your Button, copy/paste it into your Login Welcome Page, or wherever you feel it would be most appropriate. If you lose your Button Code, you\'ll need to come back &amp; re-generate a new one. If you\'re in Sandbox Test-Mode, and you\'re NOT using the Shortcode Format, please remember to come back and re-generate your Buttons before you go live.</em></p>' . "\n";
290
  /**/
301
  /**/
302
  echo '<td>' . "\n";
303
  echo '<form onsubmit="return false;">' . "\n";
304
+ echo '<p>Modification: <select id="ws-plugin--s2member-modification-level">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/membership-modification-levels.html") . '</select></p>' . "\n";
305
+ echo '<p id="ws-plugin--s2member-modification-trial-line">I\'ll offer the first <input type="text" id="ws-plugin--s2member-modification-trial-period" value="0" size="2" /> <select id="ws-plugin--s2member-modification-trial-term">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/membership-trial-terms.html") . '</select> free.</p>' . "\n";
306
+ echo '<p><span id="ws-plugin--s2member-modification-trial-then">Then, </span>I want to charge: $<input type="text" id="ws-plugin--s2member-modification-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-modification-term">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/membership-regular-terms.html") . '</select><span id="ws-plugin--s2member-modification-20p-rule"><br /><small>** Watch out for <a href="https://www.x.com/thread/41748" target="_blank" rel="external">the 20% rule</a>. Additional details on the 20% rule are <a href="https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_WPRecurringPayments#id086530108PM__id08653060UE6" target="_blank" rel="external">documented here</a>.</small></span></p>' . "\n";
307
+ echo '<p>Checkout Page Style <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can enter that Page Style here.\\n\\nIn addition. The Shortcode below, provided by s2Member; supports an image attribute: image=\\\'\\\'default\\\'\\\'. This can be changed to a full URL, pointing to a custom image of your own; instead of the default PayPal® Button image.\'); return false;">[?]</a>: <input type="text" id="ws-plugin--s2member-modification-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-modification-currency">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/currencies.html") . '</select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalButtonGenerate(\'modification\');" class="button-primary" /></p>' . "\n";
308
  echo '<p>Custom Capabilities ( comma delimited ) <a href="#" onclick="alert(\'Optional. This is VERY advanced. For full details, see:\\ns2Member -> API Scripting -> Custom Capabilities.\'); return false;">[?]</a> <input type="text" id="ws-plugin--s2member-modification-ccaps" size="40" maxlength="125" /></p>' . "\n";
309
  echo '</form>' . "\n";
310
  echo '</td>' . "\n";
350
  /**/
351
  echo '<div class="ws-menu-page-section ws-plugin--s2member-cancellation-section">' . "\n";
352
  echo '<h3>One Button Does It All For Cancellations ( copy/paste )</h3>' . "\n";
353
+ echo '<p>Since every paid Membership is associated with a PayPal® Subscription; and every PayPal® Subscription is associated with a PayPal® Account; your Members will always have a PayPal® Account of their own, which is tied to their Membership with you. So... a Member can simply log into their own PayPal® account and cancel their Subscription(s) with you at anytime, all on their own. However, some Customers do not realize this. So, if you would like to make it clearer ( easier ) for Members to cancel their own Subscription(s), you can provide this Cancellation Button for them on your Login Welcome Page, or somewhere in the support section of your website. Note... you don\'t have to use this Cancellation Button at all, if you don\'t want to. It\'s completely optional.</p>' . "\n";
354
+ echo '<p><em><strong>*Cancellation Process*</strong> Very simple. A Member clicks the Cancellation Button. PayPal® asks them to log into their PayPal® account. Once they\'re logged in, PayPal® will display a list of all active Subscriptions they have with you. They choose which ones they want to cancel, and s2Member is notified silently behind-the-scene, through the PayPal® IPN service.</em></p>' . "\n";
355
  /**/
356
  echo '<table class="form-table">' . "\n";
357
  echo '<tbody>' . "\n";
401
  /**/
402
  echo '</div>' . "\n";
403
  /**/
404
+ echo '<div class="ws-menu-page-group" title="PayPal® Specific Post/Page (Buy Now) Buttons">' . "\n";
405
  /**/
406
+ echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-buttons-section">' . "\n";
407
+ echo '<h3>Button Code Generator For Specific Post/Page Buttons</h3>' . "\n";
408
+ echo '<p>s2Member now supports an additional layer of functionality ( very powerful ), which allows you to sell access to specific Posts/Pages that you\'ve created in WordPress®. Specific Post/Page Access works independently from Member Level Access. That is, you can sell an unlimited number of Posts/Pages using "Buy Now" Buttons, and your Customers will NOT be required to have a Membership Account with your site in order to receive access. If they are already a Member, that\'s fine, but they won\'t need to be.</p>' . "\n";
409
+ echo '<p>In other words, Customers will NOT need to login, just to receive access to the Specific Post/Page they purchased access to. s2Member will immediately redirect the Customer to the Specific Post/Page after checkout is completed successfully. An email is also sent to the Customer with a link ( see: <code>s2Member -> PayPal® Options -> Specific Post/Page Email</code> ). Authentication is handled automatically through self-expiring links, good for 72 hours by default.</p>' . "\n";
410
+ echo '<p>Specific Post/Page Access, is sort of like selling a product. Only, instead of shipping anything to the Customer, you just give them access to a specific Post/Page on your site; one that you created in WordPress®. A Specific Post/Page that is protected by s2Member, might contain a download link for your eBook, access to file &amp; music downloads, access to additional support services, and the list goes on and on. The possibilities with this are endless; as long as your digital product can be delivered through access to a WordPress® Post/Page that you\'ve created. To protect Specific Posts/Pages, please see: <code>s2Member -> General Options -> Specific Post/Page Access Restrictions</code>. Once you\'ve configured your Specific Post/Page Restrictions, those Posts/Pages will be available in the menus below.</p>' . "\n";
411
+ echo '<p>Very simple. All you do is customize the form fields provided, for each Post/Page that you plan to sell. Then press (Generate Button Code). These special PayPal® Buttons are customized to work with s2Member seamlessly. You can even Package Additional Posts/Pages together into one transaction.</p>' . "\n";
412
  echo '<p><em>* Buttons are NOT saved here. This is only a Button Generator. Once you\'ve generated your Button, copy/paste it into your WordPress® Editor, wherever you feel it would be most appropriate. If you lose your Button Code, you\'ll need to come back &amp; re-generate a new one. If you\'re in Sandbox Test-Mode, and you\'re NOT using the Shortcode Format, please remember to come back and re-generate your Buttons before you go live.</em></p>' . "\n";
413
  /**/
414
  echo '<table class="form-table">' . "\n";
417
  /**/
418
  echo '<th class="ws-menu-page-th-side">' . "\n";
419
  echo '<label for="ws-plugin--s2member-sp-shortcode">' . "\n";
420
+ echo 'Button Code<br />Specific Posts/Pages:<br /><br />' . "\n";
421
  echo '<div id="ws-plugin--s2member-sp-button-prev"></div>' . "\n";
422
  echo '</label>' . "\n";
423
  echo '</th>' . "\n";
424
  /**/
425
  echo '<td>' . "\n";
426
  echo '<form onsubmit="return false;">' . "\n";
427
+ echo '<p><select id="ws-plugin--s2member-sp-leading-id">' . "\n";
428
+ echo '<option value="">&mdash; Select a Leading Post/Page that you\'ve protected &mdash;</option>' . "\n";
429
+ $ws_plugin__s2member_temp_a_pp = ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["specific_ids"]) ?/**/
430
+ array_merge ((array)get_posts ("include=" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["specific_ids"]),/**/
431
+ (array)get_pages ("include=" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["specific_ids"])) : array ();
432
+ foreach (($ws_plugin__s2member_temp_a = $ws_plugin__s2member_temp_a_pp) as $ws_plugin__s2member_temp_o)
433
+ if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"])
434
+ if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
435
+ if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_limit_exceeded_page"])
436
+ if (!in_array ($ws_plugin__s2member_temp_o->ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_pages"])))
437
+ if (!in_array ($ws_plugin__s2member_temp_o->ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_pages"])))
438
+ if (!in_array ($ws_plugin__s2member_temp_o->ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_pages"])))
439
+ if (!in_array ($ws_plugin__s2member_temp_o->ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_pages"])))
440
+ echo '<option value="' . esc_attr ($ws_plugin__s2member_temp_o->ID) . '">' . esc_html ($ws_plugin__s2member_temp_o->post_title) . '</option>' . "\n";
441
  /**/
442
+ echo '</select> <a href="#" onclick="alert(\'Required. The Leading Post/Page, is what your Customers will land on after checkout.\n\n*Tip* If there are no Posts/Pages in the menu, it\\\'s because you\\\'ve not configured s2Member for Specific Post/Page Access yet. See: s2Member -> General Options -> Specific Post/Page Access Restrictions.\'); return false;">[?]</a></p>' . "\n";
 
443
  /**/
444
+ echo '<p><select id="ws-plugin--s2member-sp-additional-ids" multiple="multiple" style="height:100px;">' . "\n";
445
+ echo '<optgroup label="&mdash; Package Additional Posts/Pages that you\'ve protected &mdash;">' . "\n";
446
+ foreach (($ws_plugin__s2member_temp_a = $ws_plugin__s2member_temp_a_pp) as $ws_plugin__s2member_temp_o)
447
  if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"])
448
  if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
449
  if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_limit_exceeded_page"])
453
  if (!in_array ($ws_plugin__s2member_temp_o->ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_pages"])))
454
  echo '<option value="' . esc_attr ($ws_plugin__s2member_temp_o->ID) . '">' . esc_html ($ws_plugin__s2member_temp_o->post_title) . '</option>' . "\n";
455
  /**/
456
+ echo '</optgroup></select> <a href="#" onclick="alert(\'Hold down your `Ctrl` key to select multiples.\\n\\nOptional. If you include Additional Posts/Pages, Customers will still land on your Leading Post/Page; BUT, they\\\'ll ALSO have access to some Additional Posts/Pages that you\\\'ve protected. This gives you the ability to create Post/Page Packages.\\n\\nIn other words, a Customer is sold a Specific Post/Page ( they\\\'ll land on your Leading Post/Page after checkout ), which might contain links to some other Posts/Pages that you\\\'ve packaged together under one transaction.\\n\\nBundling Additional Posts/Pages into one Package, authenticates the Customer for access to the Additional Posts/Pages automatically ( e.g. only one Access Link is needed, and s2Member generates this automatically ). However, you will STILL need to design your Leading Post/Page ( which is what a Customer will actually land on ), with links pointing to the other Posts/Pages. This way your Customers will have clickable links to everything they\\\'ve paid for.\\n\\n*Quick Summary* s2Member sends Customers to your Leading Post/Page, and also authenticates them for access to any Additional Posts/Pages automatically. You handle it from there.\\n\\n*Tip* If there are no Posts/Pages in this menu, it\\\'s because you\\\'ve not configured s2Member for Specific Post/Page Access yet. See: s2Member -> General Options -> Specific Post/Page Access Restrictions.\'); return false;">[?]</a></p>' . "\n";
457
+ /**/
458
  echo '<p>Description: <input type="text" id="ws-plugin--s2member-sp-desc" value="" size="68" /></p>' . "\n";
459
+ echo '<p>I want to charge: $<input type="text" id="ws-plugin--s2member-sp-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-sp-hours">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/sp-hours.html") . '</select></p>' . "\n";
460
+ echo '<p>Checkout Page Style <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can enter that Page Style here.\\n\\nIn addition. The Shortcode below, provided by s2Member; supports an image attribute: image=\\\'\\\'default\\\'\\\'. This can be changed to a full URL, pointing to a custom image of your own; instead of the default PayPal® Button image.\'); return false;">[?]</a>: <input type="text" id="ws-plugin--s2member-sp-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-sp-currency">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/currencies.html") . '</select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalSpButtonGenerate();" class="button-primary" /></p>' . "\n";
461
  echo '</form>' . "\n";
462
  echo '</td>' . "\n";
463
  /**/
488
  echo '</tr>' . "\n";
489
  echo '</tbody>' . "\n";
490
  echo '</table>' . "\n";
491
+ echo '</div>' . "\n";
492
  /**/
493
+ echo '</div>' . "\n";
494
  /**/
495
+ echo '<div class="ws-menu-page-group" title="PayPal® Specific Post/Page Access Links">' . "\n";
496
+ /**/
497
+ echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-links-section">' . "\n";
498
+ echo '<h3>Specific Post/Page Link Generator ( for Customer Service )</h3>' . "\n";
499
+ echo '<p>s2Member automatically generates Specific Post/Page Links for your Customers after checkout, and also sends them a link in a Confirmation Email. However, if you ever need to deal with a Customer Service issue that requires a new Specific Post/Page Link to be created manually, you can use this tool for that.</p>' . "\n";
500
  /**/
501
  echo '<table class="form-table">' . "\n";
502
  echo '<tbody>' . "\n";
504
  /**/
505
  echo '<td>' . "\n";
506
  echo '<form onsubmit="return false;">' . "\n";
507
+ echo '<p><select id="ws-plugin--s2member-sp-link-leading-id">' . "\n";
508
+ echo '<option value="">&mdash; Select a Leading Post/Page that you\'ve protected &mdash;</option>' . "\n";
509
+ foreach (($ws_plugin__s2member_temp_a = $ws_plugin__s2member_temp_a_pp) as $ws_plugin__s2member_temp_o)
510
+ if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"])
511
+ if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
512
+ if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_limit_exceeded_page"])
513
+ if (!in_array ($ws_plugin__s2member_temp_o->ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_pages"])))
514
+ if (!in_array ($ws_plugin__s2member_temp_o->ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_pages"])))
515
+ if (!in_array ($ws_plugin__s2member_temp_o->ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level3_pages"])))
516
+ if (!in_array ($ws_plugin__s2member_temp_o->ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_pages"])))
517
+ echo '<option value="' . esc_attr ($ws_plugin__s2member_temp_o->ID) . '">' . esc_html ($ws_plugin__s2member_temp_o->post_title) . '</option>' . "\n";
518
+ /**/
519
+ echo '</select> <a href="#" onclick="alert(\'Required. The Leading Post/Page, is what your Customers will land on after checkout.\n\n*Tip* If there are no Posts/Pages in the menu, it\\\'s because you\\\'ve not configured s2Member for Specific Post/Page Access yet. See: s2Member -> General Options -> Specific Post/Page Access Restrictions.\'); return false;">[?]</a></p>' . "\n";
520
  /**/
521
+ echo '<p><select id="ws-plugin--s2member-sp-link-additional-ids" multiple="multiple" style="height:100px;">' . "\n";
522
+ echo '<optgroup label="&mdash; Package Additional Posts/Pages that you\'ve protected &mdash;">' . "\n";
523
+ foreach (($ws_plugin__s2member_temp_a = $ws_plugin__s2member_temp_a_pp) as $ws_plugin__s2member_temp_o)
524
  if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"])
525
  if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
526
  if ($ws_plugin__s2member_temp_o->ID != $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["file_download_limit_exceeded_page"])
530
  if (!in_array ($ws_plugin__s2member_temp_o->ID, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level4_pages"])))
531
  echo '<option value="' . esc_attr ($ws_plugin__s2member_temp_o->ID) . '">' . esc_html ($ws_plugin__s2member_temp_o->post_title) . '</option>' . "\n";
532
  /**/
533
+ echo '</optgroup></select> <a href="#" onclick="alert(\'Hold down your `Ctrl` key to select multiples.\\n\\nOptional. If you include Additional Posts/Pages, Customers will still land on your Leading Post/Page; BUT, they\\\'ll ALSO have access to some Additional Posts/Pages that you\\\'ve protected. This gives you the ability to create Post/Page Packages.\\n\\nIn other words, a Customer is sold a Specific Post/Page ( they\\\'ll land on your Leading Post/Page after checkout ), which might contain links to some other Posts/Pages that you\\\'ve packaged together under one transaction.\\n\\nBundling Additional Posts/Pages into one Package, authenticates the Customer for access to the Additional Posts/Pages automatically ( e.g. only one Access Link is needed, and s2Member generates this automatically ). However, you will STILL need to design your Leading Post/Page ( which is what a Customer will actually land on ), with links pointing to the other Posts/Pages. This way your Customers will have clickable links to everything they\\\'ve paid for.\\n\\n*Quick Summary* s2Member sends Customers to your Leading Post/Page, and also authenticates them for access to any Additional Posts/Pages automatically. You handle it from there.\\n\\n*Tip* If there are no Posts/Pages in this menu, it\\\'s because you\\\'ve not configured s2Member for Specific Post/Page Access yet. See: s2Member -> General Options -> Specific Post/Page Access Restrictions.\'); return false;">[?]</a></p>' . "\n";
534
  /**/
535
+ echo '<p><select id="ws-plugin--s2member-sp-link-hours">' . file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/sp-hours.html") . '</select> <input type="button" value="Generate Access Link" onclick="ws_plugin__s2member_paypalSpLinkGenerate();" class="button-primary" /> <img id="ws-plugin--s2member-sp-link-loading" src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/ajax-loader.gif" alt="" style="display:none;" /></p>' . "\n";
536
  echo '<p id="ws-plugin--s2member-sp-link" style="font-family:Consolas, monospace; display:none;"></p>' . "\n";
537
  echo '</form>' . "\n";
538
  echo '</td>' . "\n";
includes/menu-pages/code-samples/idev-sp-tracking-code.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ idev_saleamt=%%amount%%
2
+ idev_ordernum=%%txn_id%%
3
+
4
+ <img src="http://www.example.com/idevaffiliate/sale.php
5
+ ?profile=123&idev_saleamt=%%amount%%&idev_ordernum=%%txn_id%%"
6
+ width="1" height="1" border="0" />
includes/menu-pages/code-samples/sas-sp-tracking-code.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ amount=%%amount%%
2
+ tracking=%%txn_id%%
3
+
4
+ <img src="https://shareasale.com/sale.cfm
5
+ ?amount=%%amount%%&tracking=%%txn_id%%&transtype=SALE&merchantID=123"
6
+ width="1" height="1" border="0" />
includes/menu-pages/code-samples/version.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php echo S2MEMBER_VERSION; ?>
2
+ This may output something like: 3.0.x
3
+ ( or whatever the current version number is )
4
+ Use PHP's version_compare() function to test this.
includes/menu-pages/els-ops.inc.php CHANGED
@@ -310,7 +310,7 @@ echo '<div class="ws-menu-page-group" title="Other List Server Integration Metho
310
  /**/
311
  echo '<div class="ws-menu-page-section ws-plugin--s2member-other-lists-section">' . "\n";
312
  echo '<h3>Other List Server Integrations ( there\'s always a way )</h3>' . "\n";
313
- echo '<p>Check the s2Member API Notifications panel. You\'ll find additional layers of automation available through the use of the `Signup`, `Registration`, `Payment`, `EOT/Deletion`, `Refund/Reversal`, and `Single-Page` notifications that are available to you through the s2Member API. These make it possible to integrate with 3rd party applications; like list servers, affiliate programs, and other back-office routines; in more advanced ways. You will probably need to get help from a web developer though. s2Member API Notifications require some light PHP scripting by someone familiar with web service connections.</p>' . "\n";
314
  echo '</div>' . "\n";
315
  /**/
316
  echo '</div>' . "\n";
310
  /**/
311
  echo '<div class="ws-menu-page-section ws-plugin--s2member-other-lists-section">' . "\n";
312
  echo '<h3>Other List Server Integrations ( there\'s always a way )</h3>' . "\n";
313
+ echo '<p>Check the s2Member API Notifications panel. You\'ll find additional layers of automation available through the use of the `Signup`, `Registration`, `Payment`, `EOT/Deletion`, `Refund/Reversal`, and `Specific Post/Page` notifications that are available to you through the s2Member API. These make it possible to integrate with 3rd party applications; like list servers, affiliate programs, and other back-office routines; in more advanced ways. You will probably need to get help from a web developer though. s2Member API Notifications require some light PHP scripting by someone familiar with web service connections.</p>' . "\n";
314
  echo '</div>' . "\n";
315
  /**/
316
  echo '</div>' . "\n";
includes/menu-pages/menu-pages.js CHANGED
@@ -188,9 +188,10 @@ jQuery(document).ready (function($)
188
  $('select#ws-plugin--s2member-level1-term, select#ws-plugin--s2member-level2-term, select#ws-plugin--s2member-level3-term, select#ws-plugin--s2member-level4-term, select#ws-plugin--s2member-modification-term').change (function()
189
  {
190
  var button = this.id.replace (/^ws-plugin--s2member-(.+?)-term$/g, '$1');
191
- var trialDisabled = ($(this).val ().split ('-')[1].replace (/[^A-Z]/g, '') === 'L') ? 'disabled' : '';
192
  $('p#ws-plugin--s2member-' + button + '-trial-line').css ('display', (trialDisabled ? 'none' : ''));
193
  $('span#ws-plugin--s2member-' + button + '-trial-then').css ('display', (trialDisabled ? 'none' : ''));
 
194
  });
195
  /**/
196
  $('input#ws-plugin--s2member-level1-ccaps, input#ws-plugin--s2member-level2-ccaps, input#ws-plugin--s2member-level3-ccaps, input#ws-plugin--s2member-level4-ccaps, input#ws-plugin--s2member-modification-ccaps').keyup (function()
@@ -200,7 +201,7 @@ jQuery(document).ready (function($)
200
  /**/
201
  ws_plugin__s2member_paypalButtonGenerate = function(button) /* Handles PayPal® Button Generation. */
202
  {
203
- var shortCodeTemplate = '[s2Member-PayPal-Button %%attrs%% /]', shortCodeTemplateAttrs = '', labels = {};
204
  /**/
205
  labels['level1'] = '<?php echo ws_plugin__s2member_esc_sq ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_label"]); ?>';
206
  labels['level2'] = '<?php echo ws_plugin__s2member_esc_sq ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_label"]); ?>';
@@ -218,12 +219,13 @@ jQuery(document).ready (function($)
218
  var regAmount = $('input#ws-plugin--s2member-' + button + '-amount').val ().replace (/[^0-9\.]/g, '');
219
  var regPeriod = $('select#ws-plugin--s2member-' + button + '-term').val ().split ('-')[0].replace (/[^0-9]/g, '');
220
  var regTerm = $('select#ws-plugin--s2member-' + button + '-term').val ().split ('-')[1].replace (/[^A-Z]/g, '');
221
- var regRecur = $('select#ws-plugin--s2member-' + button + '-term').val ().split ('-')[2].replace (/[^0-1]/g, '');
222
  var pageStyle = $.trim ($('input#ws-plugin--s2member-' + button + '-page-style').val ().replace (/"/g, ''));
223
  var currencyCode = $('select#ws-plugin--s2member-' + button + '-currency').val ().replace (/[^A-Z]/g, '');
224
  var cCaps = $.trim ($.trim ($('input#ws-plugin--s2member-' + button + '-ccaps').val ()).replace (/[ \-]/g, '_').replace (/[^A-Z_0-9,]/gi, '').toLowerCase ());
225
- var levelCcaps = (cCaps) ? level + ':' + cCaps : level; /* This is the combination string with custom capabilities attached to the end. */
226
- trialPeriod = (regTerm === 'L') ? '0' : trialPeriod; /* Lifetime access is NOT compatible w/trials. With lifetime access, the trialPeriod is always 0. */
 
227
  /**/
228
  if (trialTerm === 'D' && trialPeriod > 90) /* Some validation on the trial period. Max days: 90. */
229
  alert('* WARNING: Maximum Free Days is: 90.\nIf you want to offer more than 90 days free, please choose Weeks or Months from the drop-down.'), trialPeriod = 90;
@@ -236,10 +238,10 @@ jQuery(document).ready (function($)
236
  /**/
237
  code.val (code.val ().replace (/ \<\!--(\<input type\="hidden" name\="(amount|src|sra|a1|p1|t1|a3|p3|t3)" value\="(.*?)" \/\>)--\>/g, " $1"));
238
  (parseInt(trialPeriod) <= 0) ? code.val (code.val ().replace (/ (\<input type\="hidden" name\="(a1|p1|t1)" value\="(.*?)" \/\>)/g, " <!--$1-->")) : null;
239
- (regTerm === 'L') ? code.val (code.val ().replace (/ (\<input type\="hidden" name\="cmd" value\=")(.*?)(" \/\>)/g, " $1_xclick$3")) : null;
240
- (regTerm === 'L') ? code.val (code.val ().replace (/ (\<input type\="hidden" name\="(src|sra|a1|p1|t1|a3|p3|t3)" value\="(.*?)" \/\>)/g, " <!--$1-->")) : null;
241
- (regTerm !== 'L') ? code.val (code.val ().replace (/ (\<input type\="hidden" name\="cmd" value\=")(.*?)(" \/\>)/g, " $1_xclick-subscriptions$3")) : null;
242
- (regTerm !== 'L') ? code.val (code.val ().replace (/ (\<input type\="hidden" name\="amount" value\="(.*?)" \/\>)/g, " <!--$1-->")) : null;
243
  /**/
244
  shortCodeTemplateAttrs += 'level="' + level + '" ccaps="' + cCaps + '" desc="' + label + '" ps="' + pageStyle + '" cc="' + currencyCode + '" custom="<?php echo $_SERVER["HTTP_HOST"]; ?>"';
245
  shortCodeTemplateAttrs += ' tp="' + trialPeriod + '" tt="' + trialTerm + '" ra="' + regAmount + '" rp="' + regPeriod + '" rt="' + regTerm + '" rr="' + regRecur + '"';
@@ -247,7 +249,7 @@ jQuery(document).ready (function($)
247
  shortCode.val (shortCodeTemplate.replace (/%%attrs%%/, shortCodeTemplateAttrs));
248
  /**/
249
  code.val (code.val ().replace (/ name\="item_name" value\="(.*?)"/, ' name="item_name" value="' + label + '"'));
250
- code.val (code.val ().replace (/ name\="item_number" value\="(.*?)"/, ' name="item_number" value="' + levelCcaps + '"'));
251
  code.val (code.val ().replace (/ name\="page_style" value\="(.*?)"/, ' name="page_style" value="' + pageStyle + '"'));
252
  code.val (code.val ().replace (/ name\="currency_code" value\="(.*?)"/, ' name="currency_code" value="' + currencyCode + '"'));
253
  code.val (code.val ().replace (/ name\="custom" value\="(.*?)"/, ' name="custom" value="<?php echo $_SERVER["HTTP_HOST"]; ?>"'));
@@ -275,38 +277,43 @@ jQuery(document).ready (function($)
275
  return false;
276
  };
277
  /**/
278
- ws_plugin__s2member_paypalSpButtonGenerate = function() /* Handles PayPal® Button Generation for Single-Page access. */
279
  {
280
- var shortCodeTemplate = '[s2Member-PayPal-Button %%attrs%% /]', shortCodeTemplateAttrs = '';
281
  /**/
282
  var shortCode = $('input#ws-plugin--s2member-sp-shortcode');
283
  var code = $('textarea#ws-plugin--s2member-sp-button');
284
  /**/
285
- var page = $('select#ws-plugin--s2member-sp-page').val ().replace (/[^0-9]/g, '');
 
286
  var hours = $('select#ws-plugin--s2member-sp-hours').val ().replace (/[^0-9]/g, '');
287
  var desc = $.trim ($('input#ws-plugin--s2member-sp-desc').val ().replace (/"/g, ''));
288
  /**/
289
- if (!page) /* Must have a Page ID to work with. Otherwise, the purchase would fail. */
290
  {
291
- alert('Please select a Page from the drop-down.\n\nIf there are no Pages in the drop-down menu, it\'s because you\'ve not configured s2Member for Single-Page Access yet. See: s2Member -> General Options -> Single-Page Access Restrictions.');
292
  return false;
293
  }
294
- else if (!desc) /* Each Single-Page purchase should have a description. */
295
  {
296
  alert('Please type a description for this purchase.');
297
  return false;
298
  }
299
  /**/
 
 
 
 
300
  var regAmount = $('input#ws-plugin--s2member-sp-amount').val ().replace (/[^0-9\.]/g, '');
301
  var pageStyle = $.trim ($('input#ws-plugin--s2member-sp-page-style').val ().replace (/"/g, ''));
302
  var currencyCode = $('select#ws-plugin--s2member-sp-currency').val ().replace (/[^A-Z]/g, '');
303
  /**/
304
- shortCodeTemplateAttrs += 'page="' + page + '" exp="' + hours + '" desc="' + desc + '" ps="' + pageStyle + '" cc="' + currencyCode + '"';
305
  shortCodeTemplateAttrs += ' custom="<?php echo $_SERVER["HTTP_HOST"]; ?>" ra="' + regAmount + '" sp="1"';
306
  shortCode.val (shortCodeTemplate.replace (/%%attrs%%/, shortCodeTemplateAttrs));
307
  /**/
308
  code.val (code.val ().replace (/ name\="item_name" value\="(.*?)"/, ' name="item_name" value="' + desc + '"'));
309
- code.val (code.val ().replace (/ name\="item_number" value\="(.*?)"/, ' name="item_number" value="sp:' + page + ':' + hours + '"'));
310
  code.val (code.val ().replace (/ name\="page_style" value\="(.*?)"/, ' name="page_style" value="' + pageStyle + '"'));
311
  code.val (code.val ().replace (/ name\="currency_code" value\="(.*?)"/, ' name="currency_code" value="' + currencyCode + '"'));
312
  code.val (code.val ().replace (/ name\="custom" value\="(.*?)"/, ' name="custom" value="<?php echo $_SERVER["HTTP_HOST"]; ?>"'));
@@ -324,19 +331,24 @@ jQuery(document).ready (function($)
324
  return false;
325
  };
326
  /**/
327
- ws_plugin__s2member_paypalSpLinkGenerate = function() /* Handles PayPal® Link Generation for Single-Page access. */
328
  {
329
- var page = $('select#ws-plugin--s2member-sp-link-page').val ().replace (/[^0-9]/g, '');
 
330
  var hours = $('select#ws-plugin--s2member-sp-link-hours').val ().replace (/[^0-9]/g, '');
331
  var $link = $('p#ws-plugin--s2member-sp-link'), $loading = $('img#ws-plugin--s2member-sp-link-loading');
332
  /**/
333
- if (!page) /* Must have a Page ID to work with. Otherwise, link generation would fail. */
334
  {
335
- alert('Please select a Page from the drop-down.\n\nIf there are no Pages in the drop-down menu, it\'s because you\'ve not configured s2Member for Single-Page Access yet. See: s2Member -> General Options -> Single-Page Access Restrictions.');
336
  return false;
337
  }
338
  /**/
339
- $link.hide (), $loading.show (), $.post (ajaxurl, {action: 's2member_sp_access_link', s2member_sp_access_link: '<?php echo ws_plugin__s2member_esc_sq (wp_create_nonce ("ws-plugin--s2member-sp-access-link")); ?>', s2member_sp_access_link_page: page, s2member_sp_access_link_hours: hours}, function(response)
 
 
 
 
340
  {
341
  $link.show ().html ('<a href="' + response + '" target="_blank" rel="external">' + response + '</a>'), $loading.hide ();
342
  });
188
  $('select#ws-plugin--s2member-level1-term, select#ws-plugin--s2member-level2-term, select#ws-plugin--s2member-level3-term, select#ws-plugin--s2member-level4-term, select#ws-plugin--s2member-modification-term').change (function()
189
  {
190
  var button = this.id.replace (/^ws-plugin--s2member-(.+?)-term$/g, '$1');
191
+ var trialDisabled = ($(this).val ().split ('-')[2].replace (/[^0-1BN]/g, '') === 'BN') ? 1 : 0;
192
  $('p#ws-plugin--s2member-' + button + '-trial-line').css ('display', (trialDisabled ? 'none' : ''));
193
  $('span#ws-plugin--s2member-' + button + '-trial-then').css ('display', (trialDisabled ? 'none' : ''));
194
+ $('span#ws-plugin--s2member-' + button + '-20p-rule').css ('display', (trialDisabled ? 'none' : ''));
195
  });
196
  /**/
197
  $('input#ws-plugin--s2member-level1-ccaps, input#ws-plugin--s2member-level2-ccaps, input#ws-plugin--s2member-level3-ccaps, input#ws-plugin--s2member-level4-ccaps, input#ws-plugin--s2member-modification-ccaps').keyup (function()
201
  /**/
202
  ws_plugin__s2member_paypalButtonGenerate = function(button) /* Handles PayPal® Button Generation. */
203
  {
204
+ var shortCodeTemplate = '[s2Member-PayPal-Button %%attrs%% image="default" /]', shortCodeTemplateAttrs = '', labels = {};
205
  /**/
206
  labels['level1'] = '<?php echo ws_plugin__s2member_esc_sq ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_label"]); ?>';
207
  labels['level2'] = '<?php echo ws_plugin__s2member_esc_sq ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level2_label"]); ?>';
219
  var regAmount = $('input#ws-plugin--s2member-' + button + '-amount').val ().replace (/[^0-9\.]/g, '');
220
  var regPeriod = $('select#ws-plugin--s2member-' + button + '-term').val ().split ('-')[0].replace (/[^0-9]/g, '');
221
  var regTerm = $('select#ws-plugin--s2member-' + button + '-term').val ().split ('-')[1].replace (/[^A-Z]/g, '');
222
+ var regRecur = $('select#ws-plugin--s2member-' + button + '-term').val ().split ('-')[2].replace (/[^0-1BN]/g, '');
223
  var pageStyle = $.trim ($('input#ws-plugin--s2member-' + button + '-page-style').val ().replace (/"/g, ''));
224
  var currencyCode = $('select#ws-plugin--s2member-' + button + '-currency').val ().replace (/[^A-Z]/g, '');
225
  var cCaps = $.trim ($.trim ($('input#ws-plugin--s2member-' + button + '-ccaps').val ()).replace (/[ \-]/g, '_').replace (/[^A-Z_0-9,]/gi, '').toLowerCase ());
226
+ trialPeriod = (regRecur === 'BN') ? '0' : trialPeriod; /* Lifetime ( 1-L-BN ) and Buy Now ( BN ) access is NOT compatible w/ free trials. */
227
+ var levelCcapsPer = (regRecur === 'BN' && regTerm !== 'L') ? level + ':' + cCaps + ':' + regPeriod + ' ' + regTerm : level + ':' + cCaps;
228
+ levelCcapsPer = levelCcapsPer.replace (/\:+$/g, ''); /* Clean any trailing separators from this string. */
229
  /**/
230
  if (trialTerm === 'D' && trialPeriod > 90) /* Some validation on the trial period. Max days: 90. */
231
  alert('* WARNING: Maximum Free Days is: 90.\nIf you want to offer more than 90 days free, please choose Weeks or Months from the drop-down.'), trialPeriod = 90;
238
  /**/
239
  code.val (code.val ().replace (/ \<\!--(\<input type\="hidden" name\="(amount|src|sra|a1|p1|t1|a3|p3|t3)" value\="(.*?)" \/\>)--\>/g, " $1"));
240
  (parseInt(trialPeriod) <= 0) ? code.val (code.val ().replace (/ (\<input type\="hidden" name\="(a1|p1|t1)" value\="(.*?)" \/\>)/g, " <!--$1-->")) : null;
241
+ (regRecur === 'BN') ? code.val (code.val ().replace (/ (\<input type\="hidden" name\="cmd" value\=")(.*?)(" \/\>)/g, " $1_xclick$3")) : null;
242
+ (regRecur === 'BN') ? code.val (code.val ().replace (/ (\<input type\="hidden" name\="(src|sra|a1|p1|t1|a3|p3|t3)" value\="(.*?)" \/\>)/g, " <!--$1-->")) : null;
243
+ (regRecur !== 'BN') ? code.val (code.val ().replace (/ (\<input type\="hidden" name\="cmd" value\=")(.*?)(" \/\>)/g, " $1_xclick-subscriptions$3")) : null;
244
+ (regRecur !== 'BN') ? code.val (code.val ().replace (/ (\<input type\="hidden" name\="amount" value\="(.*?)" \/\>)/g, " <!--$1-->")) : null;
245
  /**/
246
  shortCodeTemplateAttrs += 'level="' + level + '" ccaps="' + cCaps + '" desc="' + label + '" ps="' + pageStyle + '" cc="' + currencyCode + '" custom="<?php echo $_SERVER["HTTP_HOST"]; ?>"';
247
  shortCodeTemplateAttrs += ' tp="' + trialPeriod + '" tt="' + trialTerm + '" ra="' + regAmount + '" rp="' + regPeriod + '" rt="' + regTerm + '" rr="' + regRecur + '"';
249
  shortCode.val (shortCodeTemplate.replace (/%%attrs%%/, shortCodeTemplateAttrs));
250
  /**/
251
  code.val (code.val ().replace (/ name\="item_name" value\="(.*?)"/, ' name="item_name" value="' + label + '"'));
252
+ code.val (code.val ().replace (/ name\="item_number" value\="(.*?)"/, ' name="item_number" value="' + levelCcapsPer + '"'));
253
  code.val (code.val ().replace (/ name\="page_style" value\="(.*?)"/, ' name="page_style" value="' + pageStyle + '"'));
254
  code.val (code.val ().replace (/ name\="currency_code" value\="(.*?)"/, ' name="currency_code" value="' + currencyCode + '"'));
255
  code.val (code.val ().replace (/ name\="custom" value\="(.*?)"/, ' name="custom" value="<?php echo $_SERVER["HTTP_HOST"]; ?>"'));
277
  return false;
278
  };
279
  /**/
280
+ ws_plugin__s2member_paypalSpButtonGenerate = function() /* Handles PayPal® Button Generation for Specific Post/Page Access. */
281
  {
282
+ var shortCodeTemplate = '[s2Member-PayPal-Button %%attrs%% image="default" /]', shortCodeTemplateAttrs = '';
283
  /**/
284
  var shortCode = $('input#ws-plugin--s2member-sp-shortcode');
285
  var code = $('textarea#ws-plugin--s2member-sp-button');
286
  /**/
287
+ var leading = $('select#ws-plugin--s2member-sp-leading-id').val ().replace (/[^0-9]/g, '');
288
+ var additionals = $('select#ws-plugin--s2member-sp-additional-ids').val () || [];
289
  var hours = $('select#ws-plugin--s2member-sp-hours').val ().replace (/[^0-9]/g, '');
290
  var desc = $.trim ($('input#ws-plugin--s2member-sp-desc').val ().replace (/"/g, ''));
291
  /**/
292
+ if (!leading) /* Must have a Leading Post/Page ID to work with. Otherwise, Link generation will fail. */
293
  {
294
+ alert('Please select a Leading Post/Page.\n\n*Tip* If there are no Posts/Pages in the menu, it\'s because you\'ve not configured s2Member for Specific Post/Page Access yet. See: s2Member -> General Options -> Specific Post/Page Access Restrictions.');
295
  return false;
296
  }
297
+ else if (!desc) /* Each Specific Post/Page purchase should have a description. */
298
  {
299
  alert('Please type a description for this purchase.');
300
  return false;
301
  }
302
  /**/
303
+ for (var i = 0, ids = leading; i < additionals.length; i++)
304
+ if (additionals[i] && additionals[i] !== leading)
305
+ ids += ',' + additionals[i];
306
+ /**/
307
  var regAmount = $('input#ws-plugin--s2member-sp-amount').val ().replace (/[^0-9\.]/g, '');
308
  var pageStyle = $.trim ($('input#ws-plugin--s2member-sp-page-style').val ().replace (/"/g, ''));
309
  var currencyCode = $('select#ws-plugin--s2member-sp-currency').val ().replace (/[^A-Z]/g, '');
310
  /**/
311
+ shortCodeTemplateAttrs += 'ids="' + ids + '" exp="' + hours + '" desc="' + desc + '" ps="' + pageStyle + '" cc="' + currencyCode + '"';
312
  shortCodeTemplateAttrs += ' custom="<?php echo $_SERVER["HTTP_HOST"]; ?>" ra="' + regAmount + '" sp="1"';
313
  shortCode.val (shortCodeTemplate.replace (/%%attrs%%/, shortCodeTemplateAttrs));
314
  /**/
315
  code.val (code.val ().replace (/ name\="item_name" value\="(.*?)"/, ' name="item_name" value="' + desc + '"'));
316
+ code.val (code.val ().replace (/ name\="item_number" value\="(.*?)"/, ' name="item_number" value="sp:' + ids + ':' + hours + '"'));
317
  code.val (code.val ().replace (/ name\="page_style" value\="(.*?)"/, ' name="page_style" value="' + pageStyle + '"'));
318
  code.val (code.val ().replace (/ name\="currency_code" value\="(.*?)"/, ' name="currency_code" value="' + currencyCode + '"'));
319
  code.val (code.val ().replace (/ name\="custom" value\="(.*?)"/, ' name="custom" value="<?php echo $_SERVER["HTTP_HOST"]; ?>"'));
331
  return false;
332
  };
333
  /**/
334
+ ws_plugin__s2member_paypalSpLinkGenerate = function() /* Handles PayPal® Link Generation for Specific Post/Page Access. */
335
  {
336
+ var leading = $('select#ws-plugin--s2member-sp-link-leading-id').val ().replace (/[^0-9]/g, '');
337
+ var additionals = $('select#ws-plugin--s2member-sp-link-additional-ids').val () || [];
338
  var hours = $('select#ws-plugin--s2member-sp-link-hours').val ().replace (/[^0-9]/g, '');
339
  var $link = $('p#ws-plugin--s2member-sp-link'), $loading = $('img#ws-plugin--s2member-sp-link-loading');
340
  /**/
341
+ if (!leading) /* Must have a Leading Post/Page ID to work with. Otherwise, Link generation will fail. */
342
  {
343
+ alert('Please select a Leading Post/Page.\n\n*Tip* If there are no Posts/Pages in the menu, it\'s because you\'ve not configured s2Member for Specific Post/Page Access yet. See: s2Member -> General Options -> Specific Post/Page Access Restrictions.');
344
  return false;
345
  }
346
  /**/
347
+ for (var i = 0, ids = leading; i < additionals.length; i++)
348
+ if (additionals[i] && additionals[i] !== leading)
349
+ ids += ',' + additionals[i];
350
+ /**/
351
+ $link.hide (), $loading.show (), $.post (ajaxurl, {action: 's2member_sp_access_link', s2member_sp_access_link: '<?php echo ws_plugin__s2member_esc_sq (wp_create_nonce ("ws-plugin--s2member-sp-access-link")); ?>', s2member_sp_access_link_ids: ids, s2member_sp_access_link_hours: hours}, function(response)
352
  {
353
  $link.show ().html ('<a href="' + response + '" target="_blank" rel="external">' + response + '</a>'), $loading.hide ();
354
  });
includes/menu-pages/options.inc.php CHANGED
@@ -113,60 +113,6 @@ echo '</div>' . "\n";
113
  /**/
114
  echo '</div>' . "\n";
115
  /**/
116
- echo '<div class="ws-menu-page-group" title="Custom Registration Fields">' . "\n";
117
- /**/
118
- echo '<div class="ws-menu-page-section ws-plugin--s2member-custom-reg-fields-section">' . "\n";
119
- echo '<h3>Custom Registration Fields ( optional, for further customization )</h3>' . "\n";
120
- echo '<p>This is a comma delimited list of additional form fields to collect during registration. By default, all of your Custom Fields will remain optional to the User. That is, the User will NOT be required to enter any of these values. If you want specific fields to be *required*, wrap those Custom Fields inside *asterisks*. Some fields are already built-in by default. The defaults are: <code>*Username*, *Email*, *First Name*, *Last Name*</code>. If you need to add other Custom Fields, in addition to these defaults, you can do that here.</p>' . "\n";
121
- if (defined ("BP_VERSION")) /* Notify the site owner about the conflict with Custom Fields and BuddyPress. */
122
- echo '<p><em class="ws-menu-page-error">* Custom Registration Fields are NOT applicable with BuddyPress. Instead, use <code>BuddyPress -> Profile Field Setup</code>.</em></p>' . "\n";
123
- if (!function_exists ("ws_plugin__s2member_generate_password"))
124
- echo '<p><em class="ws-menu-page-error">* Custom Passwords CANNOT be used with your installation of s2Member. This is due to a minor conflict with another plugin that is using <code>wp_generate_password()</code>. If you really want to allow Custom Passwords during registration, please disable some of your other plugins until this warning goes away.</em></p>' . "\n";
125
- echo '<table class="form-table">' . "\n";
126
- echo '<tbody>' . "\n";
127
- echo '<tr>' . "\n";
128
- /**/
129
- echo '<th>' . "\n";
130
- echo '<label for="ws-plugin--s2member-custom-reg-fields">' . "\n";
131
- echo 'Custom Registration Fields:' . "\n";
132
- echo '</label>' . "\n";
133
- echo '</th>' . "\n";
134
- /**/
135
- echo '</tr>' . "\n";
136
- echo '<tr>' . "\n";
137
- /**/
138
- echo '<td>' . "\n";
139
- echo '<input type="text" name="ws_plugin__s2member_custom_reg_fields" id="ws-plugin--s2member-custom-reg-fields" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_fields"]) . '" /><br />' . "\n";
140
- echo 'Comma delimited please. <em>Ex: <code>*Company*, *Website URL*, Street Address, City, State, Zip Code, Phone</code></em>' . "\n";
141
- echo '</td>' . "\n";
142
- /**/
143
- echo '</tr>' . "\n";
144
- echo '<tr>' . "\n";
145
- /**/
146
- echo '<th>' . "\n";
147
- echo '<label for="ws-plugin--s2member-custom-reg-password">' . "\n";
148
- echo 'Allow Custom Passwords during Registration?' . "\n";
149
- echo '</label>' . "\n";
150
- echo '</th>' . "\n";
151
- /**/
152
- echo '</tr>' . "\n";
153
- echo '<tr>' . "\n";
154
- /**/
155
- echo '<td>' . "\n";
156
- echo '<select name="ws_plugin__s2member_custom_reg_password" id="ws-plugin--s2member-custom-reg-password">' . "\n";
157
- echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_password"]) ? ' selected="selected"' : '') . '>No ( send auto-generated passwords via email; after registration )</option>' . "\n";
158
- echo '<option value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_password"]) ? ' selected="selected"' : '') . '>Yes ( allow members to create their own password during registration )</option>' . "\n";
159
- echo '</select><br />' . "\n";
160
- echo 'Auto-generated Passwords are recommended for best security; because, this also serves as a form of email confirmation.' . "\n";
161
- echo '</td>' . "\n";
162
- /**/
163
- echo '</tr>' . "\n";
164
- echo '</tbody>' . "\n";
165
- echo '</table>' . "\n";
166
- echo '</div>' . "\n";
167
- /**/
168
- echo '</div>' . "\n";
169
- /**/
170
  echo '<div class="ws-menu-page-group" title="Login/Registration Design">' . "\n";
171
  /**/
172
  echo '<div class="ws-menu-page-section ws-plugin--s2member-login-registration-section">' . "\n";
@@ -371,6 +317,61 @@ echo '</div>' . "\n";
371
  /**/
372
  echo '</div>' . "\n";
373
  /**/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
  echo '<div class="ws-menu-page-group" title="Login Welcome Page">' . "\n";
375
  /**/
376
  echo '<div class="ws-menu-page-section ws-plugin--s2member-login-welcome-page-section">' . "\n";
@@ -428,6 +429,57 @@ echo '</div>' . "\n";
428
  /**/
429
  echo '</div>' . "\n";
430
  /**/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
431
  echo '<div class="ws-menu-page-group" title="Membership Options Page">' . "\n";
432
  /**/
433
  echo '<div class="ws-menu-page-section ws-plugin--s2member-membership-options-page-section">' . "\n";
@@ -453,7 +505,7 @@ echo '<option value="">&mdash; Select &mdash;</option>' . "\n";
453
  foreach (($ws_plugin__s2member_temp_a = array_merge ((array)get_pages ())) as $ws_plugin__s2member_temp_o)
454
  echo '<option value="' . esc_attr ($ws_plugin__s2member_temp_o->ID) . '"' . (($ws_plugin__s2member_temp_o->ID == $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]) ? ' selected="selected"' : '') . '>' . esc_html ($ws_plugin__s2member_temp_o->post_title) . '</option>' . "\n";
455
  echo '</select><br />' . "\n";
456
- echo 'Please choose a Page that provides Users a way to signup for membership. This Page should also contain your PayPal&reg subscription button(s). We recommend the following title: <code>Membership Signup</code>.' . "\n";
457
  echo '</td>' . "\n";
458
  /**/
459
  echo '</tr>' . "\n";
@@ -550,7 +602,7 @@ echo '<div class="ws-menu-page-group" title="Post Access Restrictions">' . "\n";
550
  /**/
551
  echo '<div class="ws-menu-page-section ws-plugin--s2member-post-level-access-section">' . "\n";
552
  echo '<h3>Post Level Access Restrictions ( optional )</h3>' . "\n";
553
- echo '<p>Here you can specify Posts that are restricted to certain Membership Access Levels.</p>' . "\n";
554
  /**/
555
  echo '<table class="form-table">' . "\n";
556
  echo '<tbody>' . "\n";
@@ -957,21 +1009,22 @@ echo '</div>' . "\n";
957
  /**/
958
  echo '</div>' . "\n";
959
  /**/
960
- echo '<div class="ws-menu-page-group" title="Single-Page Access Restrictions">' . "\n";
961
  /**/
962
  echo '<div class="ws-menu-page-section ws-plugin--s2member-spage-access-section">' . "\n";
963
- echo '<h3>Single-Page Access Restrictions ( optional )</h3>' . "\n";
964
- echo '<p>s2Member now supports an additional layer of functionality ( very powerful ), which allows you to sell access to specific Pages that you\'ve created in WordPress®. Single-Page Access works independently from Member Level Access. That is, you can sell an unlimited number of Pages using "Buy Now" Buttons, and your Customers will NOT be required to have a Membership Account with your site in order to receive access. If they are already a Member, that\'s fine, but they won\'t need to be. In other words, Customers will NOT need to login, just to receive access to the Single-Page they purchased access to. s2Member will immediately redirect the Customer to the Single-Page after checkout is completed successfully. An email is also sent to the Customer with a link ( see: <code>s2Member -> PayPal® Options -> Single-Page Email</code> ). Authentication is handled automatically through IP tracking and Cookies.</p>' . "\n";
965
- echo '<p>Single-Page Access, is sort of like selling a product. Only, instead of shipping anything to the Customer, you just give them access to a specific Page on your site; one that you created in WordPress®. A Single-Page that is protected by s2Member, might contain a download link for your eBook, access to file &amp; music downloads, access to additional support services, and the list goes on and on. The possibilities with this are endless; as long as your digital product can be delivered through access to a WordPress® Page that you\'ve created.</p>' . "\n";
966
- echo '<p>Very simple. All you do is protect the Single-Page IDs that are being sold on your site. Then, you can go to <code>s2Member -> PayPal® Buttons -> Single-Page</code> to generate "Buy Now" Buttons that you can insert into your WordPress® Editor, and make available on your site.</p>' . "\n";
 
967
  /**/
968
  echo '<table class="form-table">' . "\n";
969
  echo '<tbody>' . "\n";
970
  echo '<tr>' . "\n";
971
  /**/
972
  echo '<th>' . "\n";
973
- echo '<label for="ws-plugin--s2member-single-pages">' . "\n";
974
- echo 'Single-Page IDs Being Sold On Your Site:' . "\n";
975
  echo '</label>' . "\n";
976
  echo '</th>' . "\n";
977
  /**/
@@ -979,8 +1032,8 @@ echo '</tr>' . "\n";
979
  echo '<tr>' . "\n";
980
  /**/
981
  echo '<td>' . "\n";
982
- echo '<input type="text" name="ws_plugin__s2member_single_pages" id="ws-plugin--s2member-single-pages" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["single_pages"]) . '" /><br />' . "\n";
983
- echo 'Page IDs in comma delimited format. Example: <code>1,2,3,34,8,21</code> * Note... the word <code>all</code> does NOT work here. Also, please be careful not to create a conflict with other Access Restrictions. If you are going to sell Single-Page Access, you should enter specific Page IDs here; and <strong>make SURE that you\'ve NOT already protected any of these Pages</strong>. In other words, if you configure s2Member, in such as a way, that a Page requires Membership Level Access, you cannot sell that same Page through Single-Page Access. Doing so, would create a conflict. Customers that purchased Single-Page Access, would be unable to access the Page - without also having a Membership. Not good. So be careful with this.' . "\n";
984
  echo '</td>' . "\n";
985
  /**/
986
  echo '</tr>' . "\n";
@@ -990,35 +1043,46 @@ echo '</div>' . "\n";
990
  /**/
991
  echo '</div>' . "\n";
992
  /**/
993
- echo '<div class="ws-menu-page-group" title="Member Profile Modifications">' . "\n";
994
  /**/
995
- echo '<div class="ws-menu-page-section ws-plugin--s2member-profile-modifications-section">' . "\n";
996
- echo '<h3>Giving Members The Ability To Modify Their Profile</h3>' . "\n";
997
- echo '<p>s2Member can be configured to redirect Members away from the <a href="profile.php" target="_blank" rel="external">default Profile Editing Panel</a> that is built into WordPress®. When/if a Member attempts to access the default Profile Editing Panel, they\'ll instead, be redirected to the Login Welcome Page that you\'ve configured through s2Member. <strong>Why would I redirect?</strong> Unless you\'ve made some drastic modifications to your WordPress® installation, the default Profile Editing Panel that ships with WordPress®, is NOT really suited for public access, even by a Member.</p>' . "\n";
998
- echo '<p>So instead of using this default Profile Editing Panel; s2Member creates an added layer of functionality, on top of WordPress®. It does this by providing you ( as the site owner ), with the ability to send your Members to a <a href="' . get_bloginfo ("url") . '/?s2member_profile=1" target="_blank" rel="external">special Stand-Alone page</a>, where your Members can modify their entire Profile, including all Custom Fields, and their Password. This special Stand-Alone Editing Panel, has been designed ( with a bare-bones format ), intentionally. This makes it possible for you to <a href="#" onclick="if(!window.open(\'' . get_bloginfo ("url") . '/?s2member_profile=1\', \'_popup\', \'height=350,width=400,left=100,screenX=100,top=100,screenY=100, location=0,menubar=0,toolbar=0,status=0,scrollbars=1,resizable=1\')) alert(\'Please disable popup blockers and try again!\'); return false;" rel="external">open it up in a popup window</a>, or embed it into your Login Welcome Page using an IFRAME. Code samples are provided below.</p>' . "\n";
999
- /**/
1000
- echo '<div class="ws-menu-page-hr"></div>' . "\n";
1001
- /**/
1002
- echo '<p>Stand-Alone page where Members can modify their Profile:<br />' . "\n";
1003
- echo '<code><a href="' . get_bloginfo ("url") . '/?s2member_profile=1" target="_blank" rel="external">' . get_bloginfo ("url") . '/?s2member_profile=1</a></code></p>' . "\n";
1004
  /**/
1005
- echo '<div class="ws-menu-page-hr"></div>' . "\n";
 
 
 
 
1006
  /**/
1007
- echo '<p><strong>Code Sample #1</strong> ( standard link tag ):</p>' . "\n";
1008
- echo '<p>' . highlight_string (preg_replace ("/\<\?php echo S2MEMBER_CURRENT_USER_PROFILE_MODIFICATION_PAGE_URL; \?\>/", get_bloginfo ("url") . "/?s2member_profile=1", file_get_contents (dirname (__FILE__) . "/code-samples/current-user-profile-modification-page-url-1.php")), true) . '</p>' . "\n";
1009
  /**/
1010
- echo '<p><strong>Code Sample #2</strong> ( open the link in a popup window ):</p>' . "\n";
1011
- echo '<p>' . highlight_string (preg_replace ("/\<\?php echo S2MEMBER_CURRENT_USER_PROFILE_MODIFICATION_PAGE_URL; \?\>/", get_bloginfo ("url") . "/?s2member_profile=1", file_get_contents (dirname (__FILE__) . "/code-samples/current-user-profile-modification-page-url-2.php")), true) . '</p>' . "\n";
 
 
 
 
 
 
 
 
 
 
 
 
 
1012
  /**/
1013
- echo '<p><strong>Code Sample #3</strong> ( embed the form into a Post/Page using an IFRAME tag ):</p>' . "\n";
1014
- echo '<p>' . highlight_string (preg_replace ("/\<\?php echo S2MEMBER_CURRENT_USER_PROFILE_MODIFICATION_PAGE_URL; \?\>/", get_bloginfo ("url") . "/?s2member_profile=1", file_get_contents (dirname (__FILE__) . "/code-samples/current-user-profile-modification-page-url-3.php")), true) . '</p>' . "\n";
1015
- echo '<table class="form-table">' . "\n";
1016
- echo '<tbody>' . "\n";
1017
  echo '<tr>' . "\n";
1018
  /**/
1019
  echo '<th>' . "\n";
1020
- echo '<label for="ws-plugin--s2member-force-admin-lockouts">' . "\n";
1021
- echo 'Redirect Members away from the Default Profile Panel?' . "\n";
1022
  echo '</label>' . "\n";
1023
  echo '</th>' . "\n";
1024
  /**/
@@ -1026,12 +1090,21 @@ echo '</tr>' . "\n";
1026
  echo '<tr>' . "\n";
1027
  /**/
1028
  echo '<td>' . "\n";
1029
- echo '<select name="ws_plugin__s2member_force_admin_lockouts" id="ws-plugin--s2member-force-admin-lockouts">' . "\n";
1030
- echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["force_admin_lockouts"]) ? ' selected="selected"' : '') . '>No ( I want to leave all options available to my Members )</option>' . "\n";
1031
- echo '<option value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["force_admin_lockouts"]) ? ' selected="selected"' : '') . '>Yes ( redirect Members to their Login Welcome Page )</option>' . "\n";
 
 
 
 
 
 
 
 
 
 
1032
  echo '</select><br />' . "\n";
1033
- echo 'Recommended setting ( <code>Yes</code> ). The Stand-Alone version is better.<br />' . "\n";
1034
- echo 'You\'ll want to embed the Stand-Alone version into your Login Welcome Page.<br />' . "\n";
1035
  echo '</td>' . "\n";
1036
  /**/
1037
  echo '</tr>' . "\n";
113
  /**/
114
  echo '</div>' . "\n";
115
  /**/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  echo '<div class="ws-menu-page-group" title="Login/Registration Design">' . "\n";
117
  /**/
118
  echo '<div class="ws-menu-page-section ws-plugin--s2member-login-registration-section">' . "\n";
317
  /**/
318
  echo '</div>' . "\n";
319
  /**/
320
+ echo '<div class="ws-menu-page-group" title="Custom Registration Fields">' . "\n";
321
+ /**/
322
+ echo '<div class="ws-menu-page-section ws-plugin--s2member-custom-reg-fields-section">' . "\n";
323
+ echo '<h3>Custom Registration Fields ( optional, for further customization )</h3>' . "\n";
324
+ echo '<p>This allows you to customize the Fields in your Registration Form:<br />( <a href="' . add_query_arg ("action", "register", wp_login_url ()) . '" target="_blank" rel="external">' . esc_html (add_query_arg ("action", "register", wp_login_url ())) . '</a> )</p>' . "\n";
325
+ echo '<p>This is a comma delimited list of additional form fields to collect during registration. By default, all of your Custom Fields will remain optional to the User. That is, the User will NOT be required to enter any of these values. If you want specific fields to be *required*, wrap those Custom Fields inside *asterisks*. Some fields are already built-in by default. The defaults are: <code>*Username*, *Email*, *First Name*, *Last Name*</code>. If you need to add other Custom Fields, in addition to these defaults, you can do that here.</p>' . "\n";
326
+ if (defined ("BP_VERSION")) /* Notify the site owner about the conflict with Custom Fields and BuddyPress. */
327
+ echo '<p><em class="ws-menu-page-error">* Custom Registration Fields are NOT applicable with BuddyPress. Instead, use <code>BuddyPress -> Profile Field Setup</code>.</em></p>' . "\n";
328
+ if (!function_exists ("ws_plugin__s2member_generate_password"))
329
+ echo '<p><em class="ws-menu-page-error">* Custom Passwords CANNOT be used with your installation of s2Member. This is due to a minor conflict with another plugin that is using <code>wp_generate_password()</code>. If you really want to allow Custom Passwords during registration, please disable some of your other plugins until this warning goes away.</em></p>' . "\n";
330
+ echo '<table class="form-table">' . "\n";
331
+ echo '<tbody>' . "\n";
332
+ echo '<tr>' . "\n";
333
+ /**/
334
+ echo '<th>' . "\n";
335
+ echo '<label for="ws-plugin--s2member-custom-reg-fields">' . "\n";
336
+ echo 'Custom Registration Fields:' . "\n";
337
+ echo '</label>' . "\n";
338
+ echo '</th>' . "\n";
339
+ /**/
340
+ echo '</tr>' . "\n";
341
+ echo '<tr>' . "\n";
342
+ /**/
343
+ echo '<td>' . "\n";
344
+ echo '<input type="text" name="ws_plugin__s2member_custom_reg_fields" id="ws-plugin--s2member-custom-reg-fields" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_fields"]) . '" /><br />' . "\n";
345
+ echo 'Comma delimited please. <em>Ex: <code>*Company*, *Website URL*, Street Address, City, State, Zip Code, Phone</code></em>' . "\n";
346
+ echo '</td>' . "\n";
347
+ /**/
348
+ echo '</tr>' . "\n";
349
+ echo '<tr>' . "\n";
350
+ /**/
351
+ echo '<th>' . "\n";
352
+ echo '<label for="ws-plugin--s2member-custom-reg-password">' . "\n";
353
+ echo 'Allow Custom Passwords during Registration?' . "\n";
354
+ echo '</label>' . "\n";
355
+ echo '</th>' . "\n";
356
+ /**/
357
+ echo '</tr>' . "\n";
358
+ echo '<tr>' . "\n";
359
+ /**/
360
+ echo '<td>' . "\n";
361
+ echo '<select name="ws_plugin__s2member_custom_reg_password" id="ws-plugin--s2member-custom-reg-password">' . "\n";
362
+ echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_password"]) ? ' selected="selected"' : '') . '>No ( send auto-generated passwords via email; after registration )</option>' . "\n";
363
+ echo '<option value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_password"]) ? ' selected="selected"' : '') . '>Yes ( allow members to create their own password during registration )</option>' . "\n";
364
+ echo '</select><br />' . "\n";
365
+ echo 'Auto-generated Passwords are recommended for best security; because, this also serves as a form of email confirmation.' . "\n";
366
+ echo '</td>' . "\n";
367
+ /**/
368
+ echo '</tr>' . "\n";
369
+ echo '</tbody>' . "\n";
370
+ echo '</table>' . "\n";
371
+ echo '</div>' . "\n";
372
+ /**/
373
+ echo '</div>' . "\n";
374
+ /**/
375
  echo '<div class="ws-menu-page-group" title="Login Welcome Page">' . "\n";
376
  /**/
377
  echo '<div class="ws-menu-page-section ws-plugin--s2member-login-welcome-page-section">' . "\n";
429
  /**/
430
  echo '</div>' . "\n";
431
  /**/
432
+ echo '<div class="ws-menu-page-group" title="Member Profile Modifications">' . "\n";
433
+ /**/
434
+ echo '<div class="ws-menu-page-section ws-plugin--s2member-profile-modifications-section">' . "\n";
435
+ echo '<h3>Giving Members The Ability To Modify Their Profile</h3>' . "\n";
436
+ echo '<p>s2Member can be configured to redirect Members away from the <a href="profile.php" target="_blank" rel="external">default Profile Editing Panel</a> that is built into WordPress®. When/if a Member attempts to access the default Profile Editing Panel, they\'ll instead, be redirected to the Login Welcome Page that you\'ve configured through s2Member. <strong>Why would I redirect?</strong> Unless you\'ve made some drastic modifications to your WordPress® installation, the default Profile Editing Panel that ships with WordPress®, is NOT really suited for public access, even by a Member.</p>' . "\n";
437
+ echo '<p>So instead of using this default Profile Editing Panel; s2Member creates an added layer of functionality, on top of WordPress®. It does this by providing you ( as the site owner ), with the ability to send your Members to a <a href="' . get_bloginfo ("url") . '/?s2member_profile=1" target="_blank" rel="external">special Stand-Alone page</a>, where your Members can modify their entire Profile, including all Custom Fields, and their Password. This special Stand-Alone Editing Panel, has been designed ( with a bare-bones format ), intentionally. This makes it possible for you to <a href="#" onclick="if(!window.open(\'' . get_bloginfo ("url") . '/?s2member_profile=1\', \'_popup\', \'height=350,width=400,left=100,screenX=100,top=100,screenY=100, location=0,menubar=0,toolbar=0,status=0,scrollbars=1,resizable=1\')) alert(\'Please disable popup blockers and try again!\'); return false;" rel="external">open it up in a popup window</a>, or embed it into your Login Welcome Page using an IFRAME. Code samples are provided below.</p>' . "\n";
438
+ /**/
439
+ echo '<div class="ws-menu-page-hr"></div>' . "\n";
440
+ /**/
441
+ echo '<p>Stand-Alone page where Members can modify their Profile:<br />' . "\n";
442
+ echo '<code><a href="' . get_bloginfo ("url") . '/?s2member_profile=1" target="_blank" rel="external">' . get_bloginfo ("url") . '/?s2member_profile=1</a></code></p>' . "\n";
443
+ /**/
444
+ echo '<div class="ws-menu-page-hr"></div>' . "\n";
445
+ /**/
446
+ echo '<p><strong>Code Sample #1</strong> ( standard link tag ):</p>' . "\n";
447
+ echo '<p>' . highlight_string (preg_replace ("/\<\?php echo S2MEMBER_CURRENT_USER_PROFILE_MODIFICATION_PAGE_URL; \?\>/", get_bloginfo ("url") . "/?s2member_profile=1", file_get_contents (dirname (__FILE__) . "/code-samples/current-user-profile-modification-page-url-1.php")), true) . '</p>' . "\n";
448
+ /**/
449
+ echo '<p><strong>Code Sample #2</strong> ( open the link in a popup window ):</p>' . "\n";
450
+ echo '<p>' . highlight_string (preg_replace ("/\<\?php echo S2MEMBER_CURRENT_USER_PROFILE_MODIFICATION_PAGE_URL; \?\>/", get_bloginfo ("url") . "/?s2member_profile=1", file_get_contents (dirname (__FILE__) . "/code-samples/current-user-profile-modification-page-url-2.php")), true) . '</p>' . "\n";
451
+ /**/
452
+ echo '<p><strong>Code Sample #3</strong> ( embed the form into a Post/Page using an IFRAME tag ):</p>' . "\n";
453
+ echo '<p>' . highlight_string (preg_replace ("/\<\?php echo S2MEMBER_CURRENT_USER_PROFILE_MODIFICATION_PAGE_URL; \?\>/", get_bloginfo ("url") . "/?s2member_profile=1", file_get_contents (dirname (__FILE__) . "/code-samples/current-user-profile-modification-page-url-3.php")), true) . '</p>' . "\n";
454
+ echo '<table class="form-table">' . "\n";
455
+ echo '<tbody>' . "\n";
456
+ echo '<tr>' . "\n";
457
+ /**/
458
+ echo '<th>' . "\n";
459
+ echo '<label for="ws-plugin--s2member-force-admin-lockouts">' . "\n";
460
+ echo 'Redirect Members away from the Default Profile Panel?' . "\n";
461
+ echo '</label>' . "\n";
462
+ echo '</th>' . "\n";
463
+ /**/
464
+ echo '</tr>' . "\n";
465
+ echo '<tr>' . "\n";
466
+ /**/
467
+ echo '<td>' . "\n";
468
+ echo '<select name="ws_plugin__s2member_force_admin_lockouts" id="ws-plugin--s2member-force-admin-lockouts">' . "\n";
469
+ echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["force_admin_lockouts"]) ? ' selected="selected"' : '') . '>No ( I want to leave all options available to my Members )</option>' . "\n";
470
+ echo '<option value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["force_admin_lockouts"]) ? ' selected="selected"' : '') . '>Yes ( redirect Members to their Login Welcome Page )</option>' . "\n";
471
+ echo '</select><br />' . "\n";
472
+ echo 'Recommended setting ( <code>Yes</code> ). The Stand-Alone version is better.<br />' . "\n";
473
+ echo 'You\'ll want to embed the Stand-Alone version into your Login Welcome Page.<br />' . "\n";
474
+ echo '</td>' . "\n";
475
+ /**/
476
+ echo '</tr>' . "\n";
477
+ echo '</tbody>' . "\n";
478
+ echo '</table>' . "\n";
479
+ echo '</div>' . "\n";
480
+ /**/
481
+ echo '</div>' . "\n";
482
+ /**/
483
  echo '<div class="ws-menu-page-group" title="Membership Options Page">' . "\n";
484
  /**/
485
  echo '<div class="ws-menu-page-section ws-plugin--s2member-membership-options-page-section">' . "\n";
505
  foreach (($ws_plugin__s2member_temp_a = array_merge ((array)get_pages ())) as $ws_plugin__s2member_temp_o)
506
  echo '<option value="' . esc_attr ($ws_plugin__s2member_temp_o->ID) . '"' . (($ws_plugin__s2member_temp_o->ID == $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]) ? ' selected="selected"' : '') . '>' . esc_html ($ws_plugin__s2member_temp_o->post_title) . '</option>' . "\n";
507
  echo '</select><br />' . "\n";
508
+ echo 'Please choose a Page that provides Users a way to signup for membership. This Page should also contain your PayPal&reg Subscription button(s). We recommend the following title: <code>Membership Signup</code>.' . "\n";
509
  echo '</td>' . "\n";
510
  /**/
511
  echo '</tr>' . "\n";
602
  /**/
603
  echo '<div class="ws-menu-page-section ws-plugin--s2member-post-level-access-section">' . "\n";
604
  echo '<h3>Post Level Access Restrictions ( optional )</h3>' . "\n";
605
+ echo '<p>Here you can specify Posts that are restricted to certain Membership Access Levels. These fields also support Custom Post Types, which were first introduced in WordPress® 3.0. If you have a theme/plugin installed that has enabled Custom Post Types ( i.e. Music/Videos/etc ), you can put the IDs for those Posts here.</p>' . "\n";
606
  /**/
607
  echo '<table class="form-table">' . "\n";
608
  echo '<tbody>' . "\n";
1009
  /**/
1010
  echo '</div>' . "\n";
1011
  /**/
1012
+ echo '<div class="ws-menu-page-group" title="Specific Post/Page Access Restrictions">' . "\n";
1013
  /**/
1014
  echo '<div class="ws-menu-page-section ws-plugin--s2member-spage-access-section">' . "\n";
1015
+ echo '<h3>Specific Post/Page Access Restrictions ( optional )</h3>' . "\n";
1016
+ echo '<p>s2Member now supports an additional layer of functionality ( very powerful ), which allows you to sell access to specific Posts/Pages that you\'ve created in WordPress®. Specific Post/Page Access works independently from Member Level Access. That is, you can sell an unlimited number of Posts/Pages using "Buy Now" Buttons, and your Customers will NOT be required to have a Membership Account with your site in order to receive access. If they are already a Member, that\'s fine, but they won\'t need to be.</p>' . "\n";
1017
+ echo '<p>In other words, Customers will NOT need to login, just to receive access to the Specific Post/Page they purchased access to. s2Member will immediately redirect the Customer to the Specific Post/Page after checkout is completed successfully. An email is also sent to the Customer with a link ( see: <code>s2Member -> PayPal® Options -> Specific Post/Page Email</code> ). Authentication is handled automatically through self-expiring links, good for 72 hours by default.</p>' . "\n";
1018
+ echo '<p>Specific Post/Page Access, is sort of like selling a product. Only, instead of shipping anything to the Customer, you just give them access to a specific Post/Page on your site; one that you created in WordPress®. A Specific Post/Page that is protected by s2Member, might contain a download link for your eBook, access to file &amp; music downloads, access to additional support services, and the list goes on and on. The possibilities with this are endless; as long as your digital product can be delivered through access to a WordPress® Post/Page that you\'ve created.</p>' . "\n";
1019
+ echo '<p>Very simple. All you do is protect the Specific Post/Page IDs that are being sold on your site. Then, you can go to <code>s2Member -> PayPal® Buttons -> Specific Post/Page</code> to generate "Buy Now" Buttons that you can insert into your WordPress® Editor, and make available on your site. The Button Generator for s2Member, will even let you Package Additional Posts/Pages together into one transaction.</p>' . "\n";
1020
  /**/
1021
  echo '<table class="form-table">' . "\n";
1022
  echo '<tbody>' . "\n";
1023
  echo '<tr>' . "\n";
1024
  /**/
1025
  echo '<th>' . "\n";
1026
+ echo '<label for="ws-plugin--s2member-specific-ids">' . "\n";
1027
+ echo 'Specific Post/Page IDs Being Sold On Your Site:' . "\n";
1028
  echo '</label>' . "\n";
1029
  echo '</th>' . "\n";
1030
  /**/
1032
  echo '<tr>' . "\n";
1033
  /**/
1034
  echo '<td>' . "\n";
1035
+ echo '<input type="text" name="ws_plugin__s2member_specific_ids" id="ws-plugin--s2member-specific-ids" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["specific_ids"]) . '" /><br />' . "\n";
1036
+ echo 'Post/Page IDs in comma delimited format. Example: <code>1,2,3,34,8,21</code> * Note... the word <code>all</code> does NOT work here. Also, please be careful not to create a conflict with other Access Restrictions. If you are going to sell Specific Post/Page Access, you should enter specific Post/Page IDs here; and <strong>make SURE that you\'ve NOT already protected any of these Posts/Pages with Member Level Access Restrictions</strong>. In other words, if you configure s2Member, in such as a way, that a Post/Page requires Membership Level Access, you cannot sell that same Post/Page through Specific Post/Page Access. Doing so, would create a conflict. Customers that purchased Specific Post/Page Access, would be unable to access the Post/Page - without also having a Membership. Not good. So be careful with this.' . "\n";
1037
  echo '</td>' . "\n";
1038
  /**/
1039
  echo '</tr>' . "\n";
1043
  /**/
1044
  echo '</div>' . "\n";
1045
  /**/
1046
+ echo '<div class="ws-menu-page-group" title="Unique IP Access Restrictions">' . "\n";
1047
  /**/
1048
+ echo '<div class="ws-menu-page-section ws-plugin--s2member-ip-restrictions-section">' . "\n";
1049
+ echo '<h3>Unique IP Access Restrictions ( prevents username/link sharing )</h3>' . "\n";
1050
+ echo '<p>As with any membership system, it is possible for one Member to signup, and then share their Username with someone else; or even post it online for the whole world to see. This is known as Link Sharing ( aka: Username Sharing ). It is not likely that you\'ll be attacked in this way, but it\'s still a good idea to protect your system; just in case somebody tries this. s2Member\'s IP Restrictions, work for both Membership Level Access ( account logins ), and also for Specific Post/Page Access. In both cases, the rules are simple. A single Username, and/or Access Link is only valid for a certain number of unique IP addresses. Once that limit is reached, s2Member assumes there has been a security breach. At that time, s2Member will place a temporary ban ( preventing access ) to a Specific Post/Page, or to an account associated with a particular Username. This temporary ban, will ONLY affect the offending Link and/or Username associated with the security breach.</p>' . "\n";
1051
+ echo '<table class="form-table">' . "\n";
1052
+ echo '<tbody>' . "\n";
1053
+ echo '<tr>' . "\n";
 
 
 
1054
  /**/
1055
+ echo '<th>' . "\n";
1056
+ echo '<label for="ws-plugin--s2member-max-ip-restriction">' . "\n";
1057
+ echo 'Maximum Unique IP Addresses Allowed:' . "\n";
1058
+ echo '</label>' . "\n";
1059
+ echo '</th>' . "\n";
1060
  /**/
1061
+ echo '</tr>' . "\n";
1062
+ echo '<tr>' . "\n";
1063
  /**/
1064
+ echo '<td>' . "\n";
1065
+ echo '<select name="ws_plugin__s2member_max_ip_restriction" id="ws-plugin--s2member-max-ip-restriction">' . "\n";
1066
+ echo '<option value="2"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 2) ? ' selected="selected"' : '') . '>Allow up to 2 different IPs per Customer</option>' . "\n";
1067
+ echo '<option value="3"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 3) ? ' selected="selected"' : '') . '>Allow up to 3 different IPs per Customer</option>' . "\n";
1068
+ echo '<option value="4"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 4) ? ' selected="selected"' : '') . '>Allow up to 4 different IPs per Customer</option>' . "\n";
1069
+ echo '<option value="5"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 5) ? ' selected="selected"' : '') . '>Allow up to 5 different IPs per Customer</option>' . "\n";
1070
+ echo '<option value="10"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 10) ? ' selected="selected"' : '') . '>Allow up to 10 different IPs per Customer</option>' . "\n";
1071
+ echo '<option value="20"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 20) ? ' selected="selected"' : '') . '>Allow up to 20 different IPs per Customer</option>' . "\n";
1072
+ echo '<option value="30"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 30) ? ' selected="selected"' : '') . '>Allow up to 30 different IPs per Customer</option>' . "\n";
1073
+ echo '<option value="40"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 40) ? ' selected="selected"' : '') . '>Allow up to 40 different IPs per Customer</option>' . "\n";
1074
+ echo '<option value="50"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 50) ? ' selected="selected"' : '') . '>Allow up to 50 different IPs per Customer</option>' . "\n";
1075
+ echo '<option value="75"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 75) ? ' selected="selected"' : '') . '>Allow up to 75 different IPs per Customer</option>' . "\n";
1076
+ echo '<option value="100"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 100) ? ' selected="selected"' : '') . '>Allow up to 100 different IPs per Customer</option>' . "\n";
1077
+ echo '</select><br />' . "\n";
1078
+ echo '</td>' . "\n";
1079
  /**/
1080
+ echo '</tr>' . "\n";
 
 
 
1081
  echo '<tr>' . "\n";
1082
  /**/
1083
  echo '<th>' . "\n";
1084
+ echo '<label for="ws-plugin--s2member-max-ip-restriction-time">' . "\n";
1085
+ echo 'Security Breach Timeout Period:' . "\n";
1086
  echo '</label>' . "\n";
1087
  echo '</th>' . "\n";
1088
  /**/
1090
  echo '<tr>' . "\n";
1091
  /**/
1092
  echo '<td>' . "\n";
1093
+ echo '<select name="ws_plugin__s2member_max_ip_restriction_time" id="ws-plugin--s2member-max-ip-restriction-time">' . "\n";
1094
+ echo '<option value="900"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction_time"] == 900) ? ' selected="selected"' : '') . '>If limit is exceeded ( punish for 15 mins )</option>' . "\n";
1095
+ echo '<option value="1800"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction_time"] == 1800) ? ' selected="selected"' : '') . '>If limit is exceeded ( punish for 30 mins )</option>' . "\n";
1096
+ echo '<option value="3600"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction_time"] == 3600) ? ' selected="selected"' : '') . '>If limit is exceeded ( punish for 1 hour )</option>' . "\n";
1097
+ echo '<option value="7200"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction_time"] == 7200) ? ' selected="selected"' : '') . '>If limit is exceeded ( punish for 2 hours )</option>' . "\n";
1098
+ echo '<option value="14400"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction_time"] == 14400) ? ' selected="selected"' : '') . '>If limit is exceeded ( punish for 4 hours )</option>' . "\n";
1099
+ echo '<option value="21600"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction_time"] == 21600) ? ' selected="selected"' : '') . '>If limit is exceeded ( punish for 6 hours )</option>' . "\n";
1100
+ echo '<option value="28800"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction_time"] == 28800) ? ' selected="selected"' : '') . '>If limit is exceeded ( punish for 8 hours )</option>' . "\n";
1101
+ echo '<option value="43200"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction_time"] == 43200) ? ' selected="selected"' : '') . '>If limit is exceeded ( punish for 12 hours )</option>' . "\n";
1102
+ echo '<option value="86400"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction_time"] == 86400) ? ' selected="selected"' : '') . '>If limit is exceeded ( punish for 24 hours )</option>' . "\n";
1103
+ echo '<option value="172800"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction_time"] == 172800) ? ' selected="selected"' : '') . '>If limit is exceeded ( punish for 2 days )</option>' . "\n";
1104
+ echo '<option value="345600"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction_time"] == 345600) ? ' selected="selected"' : '') . '>If limit is exceeded ( punish for 4 days )</option>' . "\n";
1105
+ echo '<option value="604800"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction_time"] == 604800) ? ' selected="selected"' : '') . '>If limit is exceeded ( punish for 1 week )</option>' . "\n";
1106
  echo '</select><br />' . "\n";
1107
+ echo 'When/if you change this, it will take X amount of time to update; based on your previous configuration.' . "\n";
 
1108
  echo '</td>' . "\n";
1109
  /**/
1110
  echo '</tr>' . "\n";
includes/menu-pages/paypal-ops.inc.php CHANGED
@@ -106,8 +106,9 @@ echo '<h3>PayPal® IPN / Instant Payment Notifications ( required, please enable
106
  echo '<p>Log into your PayPal® account and navigate to this section:<br /><code>Account Profile -> Instant Payment Notification Preferences</code></p>' . "\n";
107
  echo '<p>Edit your IPN settings &amp; turn IPN Notifications: <strong><code>On</code></strong></p>' . "\n";
108
  echo '<p>You\'ll need your IPN URL, which is:<br /><code>' . get_bloginfo ("url") . '/?s2member_paypal_notify=1</code></p>' . "\n";
109
- echo '<p><em><strong>*Quick tip*</strong> In addition to the default IPN Settings inside your PayPal® account, the IPN URL is also set on a per-transaction basis by the special PayPal® Button Code that s2Member provides you with. In other words, if you have multiple sites operating on one PayPal® account, that\'s OK. s2Member dynamically sets the IPN URL for each transaction. The result is that the IPN URL configured from within your PayPal® account, becomes the default, which is then overwritten on a per transaction basis. In fact, PayPal® recently updated their system to support IPN URL preservation. One PayPal® account can handle multiple sites, all using different IPN URLs.</em></p>' . "\n";
110
- echo '<p><em><strong>*More information*</strong> You\'ll be happy to know that s2Member handles cancellations, expirations, failed payments ( more than 2 in a row ), terminations ( e.g. refunds &amp; chargebacks ) for you automatically. If you log into your PayPal® account and cancel a Member\'s subscription, or, if the Member logs into their PayPal® account and cancels their own subscription, s2Member will be notified of these important changes and react accordingly through the PayPal® IPN service that runs silently behind-the-scene. The PayPal® IPN service will notify s2Member whenever a Member\'s payments have been failing ( more than 2 times in a row ), and/or whenever a Member\'s subscription has expired for any reason. Even refunds &amp; chargeback reversals are supported through the IPN service. If you issue a refund to an unhappy Customer through PayPal®, s2Member will be notified, and the account for that Customer will either be demoted to a Free Subscriber, or deleted automatically ( based on your configuration ). The communication from PayPal® -> s2Member is seamless.</em></p>' . "\n";
 
111
  echo '</div>' . "\n";
112
  /**/
113
  echo '</div>' . "\n";
@@ -120,7 +121,7 @@ echo '<p>Log into your PayPal® account and navigate to this section:<br /><code
120
  echo '<p>Turn the Auto-Return feature: <strong><code>On</code></strong></p>' . "\n";
121
  echo '<p>You\'ll need your Auto-Return URL, which is:<br /><code>' . get_bloginfo ("url") . '/?s2member_paypal_return=1</code></p>' . "\n";
122
  echo '<p>You MUST also enable PDT ( Payment Data Transfer ): <strong><code>On</code></strong><br /><em>You\'ll be issued an Identity Token that you MUST enter below.</em></p>' . "\n";
123
- echo '<p><em><strong>*Quick tip*</strong> In addition to your default PayPal® account configuration, the Auto-Return URL is also set on a per-transaction basis from within the special PayPal® Button Code that s2Member provides you with. In other words, if you have multiple sites operating on one PayPal® account, that\'s OK. s2Member dynamically sets the Auto-Return URL for each transaction. The result is that the Auto-Return URL configured from within your PayPal® account, becomes the default, which is then overwritten on a per transaction basis.</em></p>' . "\n";
124
  /**/
125
  echo '<table class="form-table">' . "\n";
126
  echo '<tbody>' . "\n";
@@ -189,26 +190,26 @@ echo 'Message Body used in the email sent to a Customer after a successful signu
189
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
190
  echo '<ul>' . "\n";
191
  echo '<li><code>%%registration_url%% = The full URL ( generated by s2Member ) where the Customer can get registered.</code></li>' . "\n";
192
- echo '<li><code>%%subscr_id%% = The PayPal® Subscription ID, which remains constant throughout any &amp; all future payments.</code> [ <a href="#" onclick="alert(\'There is one exception. If you are selling Lifetime ( non-recurring ) access, using a Buy It Now button; the %%subscr_id%% is actually set to the Transaction ID for the purchase.\\n\\nPayPal® does not provide a specific Subscription ID for Buy It Now purchases. Since Lifetime subscriptions are NOT recurring ( i.e. there is only ONE payment ), using the Transaction ID as the Subscription ID is a graceful way to deal with this minor conflict.\'); return false;">?</a> ]</li>' . "\n";
193
  echo '<li><code>%%initial%% = The Initial Fee charged during signup. If you offered a free trial, this will be 0.</code> [ <a href="#" onclick="alert(\'This will always represent the amount of money the Customer spent, whenever they initially signed up, no matter what. If a Customer signs up, under the terms of a free trial period, this will be 0.\'); return false;">?</a> ]</li>' . "\n";
194
- echo '<li><code>%%regular%% = The Regular Amount of the subscription. This value is always > 0, no matter what.</code> [ <a href="#" onclick="alert(\'This is how much the subscription costs after an initial period expires. The %%regular%% rate is always > 0. If you did not offer an initial period, %%initial%% and %%regular%% will be equal to the same thing.\'); return false;">?</a> ]</li>' . "\n";
195
- echo '<li><code>%%recurring%% = This is the amount that will be charged on a Recurring basis, or 0 if non-Recurring.</code> [ <a href="#" onclick="alert(\'If recurring payments have not been required, this will be equal to 0. That being said, %%regular%% &amp; %%recurring%% are usually the same value. This variable can be used in two different ways. You can use it to determine what the regular recurring rate is, or to determine whether the subscription will recur or not. If it is going to recur, %%recurring%% will be > 0.\\n\\nThe only time this is NOT equal to the %%regular%% rate, is when recurring payments are not required; and only a one-time regular rate applies.\'); return false;">?</a> ]</li>' . "\n";
196
- echo '<li><code>%%first_name%% = The First Name of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
197
- echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
198
- echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased the membership subscription.</code></li>' . "\n";
199
- echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
200
- echo '<li><code>%%item_number%% = The Item Number ( colon separated <em>level:custom_capabilities</em> ) that the subscription is for.</code></li>' . "\n";
201
  echo '<li><code>%%item_name%% = The Item Name ( in other words, the associated membership Level Label that briefly describes the item number ).</code></li>' . "\n";
202
- echo '<li><code>%%initial_term%% = This is the term length of the initial period. This will be a numeric value, followed by a space, then a single letter.</code> [ <a href="#" onclick="alert(\'Here are some examples:\\n\\n%%initial_term%% = 1 D ( this means 1 Day )\\n%%initial_term%% = 1 M ( this means 1 Month )\\n%%initial_term%% = 1 Y ( this means 1 Year )\\n\\nThe initial period never recurs, so this only lasts for the term length specified, then it is over. If no initial period was even offered, the value of %%initial_term%% will just be: 0 D, meaning zero days.\'); return false;">?</a> ]</li>' . "\n";
203
- echo '<li><code>%%regular_term%% = This is the term length of the regular period. This will be a numeric value, followed by a space, then a single letter.</code> [ <a href="#" onclick="alert(\'Here are some examples:\\n\\n%%regular_term%% = 1 D ( this means 1 Day )\\n%%regular_term%% = 1 M ( this means 1 Month )\\n%%regular_term%% = 1 Y ( this means 1 Year )\\n%%regular_term%% = 1 L ( this means 1 Lifetime )\\n\\nThe regular term is usually recurring. So the regular term value represents the period ( or duration ) of each recurring period. If %%recurring%% = 0, then the regular term only applies once, because it is not recurring. So if it is not recurring, the value of %%regular_term%% simply represents how long their membership privileges are going to last after the %%initial_term%% has expired, if there was an initial term. The value of this variable ( %%regular_term%% ) will never be empty, it will always be at least: 1 D, meaning 1 day. No exceptions.\'); return false;">?</a> ]</li>' . "\n";
204
  echo '</ul>' . "\n";
205
  echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
206
  echo '<ul>' . "\n";
207
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
208
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
209
  echo '</ul>' . "\n";
210
- echo '<strong>This example uses cv1 to track a user\'s IP address:</strong><br />' . "\n";
211
- echo '<em>( The IP address can be referenced in your Confirmation Email using %%cv1%% )</em><br />' . "\n";
212
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
213
  echo '</td>' . "\n";
214
  /**/
@@ -219,19 +220,19 @@ echo '</div>' . "\n";
219
  /**/
220
  echo '</div>' . "\n";
221
  /**/
222
- echo '<div class="ws-menu-page-group" title="PayPal® Single-Page Email">' . "\n";
223
  /**/
224
- echo '<div class="ws-menu-page-section ws-plugin--s2member-single-page-email-section">' . "\n";
225
- echo '<h3>Single-Page Confirmation Email ( required, but the default works fine )</h3>' . "\n";
226
- echo '<p>This email is sent to new Customers after they return from a successful purchase at PayPal®, specifically for Single-Page Access. ( see: <code>s2Member -> General Options -> Single-Page Access</code> ). This is NOT used for Membership sales, only for Single-Page Access. The <strong>primary</strong> purpose of this email, is to provide the Customer with instructions, along with a link to access the Page they\'ve obtained access to. You may also customize this further by providing details that are specifically geared to your site.</p>' . "\n";
227
  /**/
228
  echo '<table class="form-table">' . "\n";
229
  echo '<tbody>' . "\n";
230
  echo '<tr>' . "\n";
231
  /**/
232
  echo '<th>' . "\n";
233
- echo '<label for="ws-plugin--s2member-single-page-email-subject">' . "\n";
234
- echo 'Single-Page Confirmation Email Subject:' . "\n";
235
  echo '</label>' . "\n";
236
  echo '</th>' . "\n";
237
  /**/
@@ -239,16 +240,16 @@ echo '</tr>' . "\n";
239
  echo '<tr>' . "\n";
240
  /**/
241
  echo '<td>' . "\n";
242
- echo '<input type="text" name="ws_plugin__s2member_single_page_email_subject" id="ws-plugin--s2member-single-page-email-subject" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["single_page_email_subject"]) . '" /><br />' . "\n";
243
- echo 'Subject Line used in the email sent to a Customer after a successful purchase has occurred through PayPal® for Single-Page Access.' . "\n";
244
  echo '</td>' . "\n";
245
  /**/
246
  echo '</tr>' . "\n";
247
  echo '<tr>' . "\n";
248
  /**/
249
  echo '<th>' . "\n";
250
- echo '<label for="ws-plugin--s2member-single-page-email-message">' . "\n";
251
- echo 'Single-Page Confirmation Email Message:' . "\n";
252
  echo '</label>' . "\n";
253
  echo '</th>' . "\n";
254
  /**/
@@ -256,19 +257,19 @@ echo '</tr>' . "\n";
256
  echo '<tr>' . "\n";
257
  /**/
258
  echo '<td>' . "\n";
259
- echo '<textarea name="ws_plugin__s2member_single_page_email_message" id="ws-plugin--s2member-single-page-email-message" rows="10">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["single_page_email_message"]) . '</textarea><br />' . "\n";
260
- echo 'Message Body used in the email sent to a Customer after a successful purchase has occurred through PayPal® for Single-Page Access.<br /><br />' . "\n";
261
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
262
  echo '<ul>' . "\n";
263
  echo '<li><code>%%sp_access_url%% = The full URL ( generated by s2Member ) where the Customer can gain access.</code></li>' . "\n";
264
  echo '<li><code>%%sp_access_exp%% = Human readable expiration for %%sp_access_url%%. Ex: <em>( link expires in %%sp_access_exp%% )</em>.</code></li>' . "\n";
265
  echo '<li><code>%%txn_id%% = The PayPal® Transaction ID. PayPal® assigns a unique identifier for every purchase.</code></li>' . "\n";
266
- echo '<li><code>%%amount%% = The full Amount that you charged for Single-Page Access. This value will always be > 0.</code></li>' . "\n";
267
- echo '<li><code>%%first_name%% = The First Name of the Customer who purchased Single-Page Access through PayPal®.</code></li>' . "\n";
268
- echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased Single-Page Access through PayPal®.</code></li>' . "\n";
269
- echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased Single-Page Access.</code></li>' . "\n";
270
- echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased Single-Page Access through PayPal®.</code></li>' . "\n";
271
- echo '<li><code>%%item_number%% = The Item Number. Ex: <em>sp:13:72</em> ( sp:page_ID:expiration_hours ).</code></li>' . "\n";
272
  echo '<li><code>%%item_name%% = The Item Name. In other words, a brief description, detailing what this purchase was for.</code></li>' . "\n";
273
  echo '</ul>' . "\n";
274
  echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
@@ -276,8 +277,8 @@ echo '<ul>' . "\n";
276
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
277
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
278
  echo '</ul>' . "\n";
279
- echo '<strong>This example uses cv1 to track a user\'s IP address:</strong><br />' . "\n";
280
- echo '<em>( The IP address can be referenced in your Confirmation Email using %%cv1%% )</em><br />' . "\n";
281
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
282
  echo '</td>' . "\n";
283
  /**/
@@ -292,12 +293,33 @@ echo '<div class="ws-menu-page-group" title="PayPal® EOT Behavior">' . "\n";
292
  /**/
293
  echo '<div class="ws-menu-page-section ws-plugin--s2member-eot-behavior-section">' . "\n";
294
  echo '<h3>PayPal® EOT Behavior ( required, please choose )</h3>' . "\n";
295
- echo '<p>EOT = End Of Term. By default, s2Member will demote a paid Member to a Free Subscriber whenever their subscription term has ended, been canceled, refunded, charged back to you, etc. s2Member demotes them to a Free Subscriber, so they will no longer have paid Member Level Access to your site. However, in some cases, you may prefer to have Customer accounts deleted completely, instead of just being demoted. This is where you choose which method works best for your site.</p>' . "\n";
296
  echo '<table class="form-table">' . "\n";
297
  echo '<tbody>' . "\n";
298
  echo '<tr>' . "\n";
299
  /**/
300
  echo '<th>' . "\n";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  echo '<label for="ws-plugin--s2member-membership-eot-behavior">' . "\n";
302
  echo 'Membership EOT Behavior ( demote or delete )?' . "\n";
303
  echo '</label>' . "\n";
106
  echo '<p>Log into your PayPal® account and navigate to this section:<br /><code>Account Profile -> Instant Payment Notification Preferences</code></p>' . "\n";
107
  echo '<p>Edit your IPN settings &amp; turn IPN Notifications: <strong><code>On</code></strong></p>' . "\n";
108
  echo '<p>You\'ll need your IPN URL, which is:<br /><code>' . get_bloginfo ("url") . '/?s2member_paypal_notify=1</code></p>' . "\n";
109
+ echo '<p><em><strong>*Quick Tip*</strong> In addition to the default IPN Settings inside your PayPal® account, the IPN URL is also set on a per-transaction basis by the special PayPal® Button Code that s2Member provides you with. In other words, if you have multiple sites operating on one PayPal® account, that\'s OK. s2Member dynamically sets the IPN URL for each transaction. The result is that the IPN URL configured from within your PayPal® account, becomes the default, which is then overwritten on a per transaction basis. In fact, PayPal® recently updated their system to support IPN URL preservation. One PayPal® account can handle multiple sites, all using different IPN URLs.</em></p>' . "\n";
110
+ echo '<p><em><strong>*More Information*</strong> You\'ll be happy to know that s2Member handles cancellations, expirations, failed payments ( more than 2 in a row ), terminations ( e.g. refunds &amp; chargebacks ) for you automatically. If you log into your PayPal® account and cancel a Member\'s Subscription, or, if the Member logs into their PayPal® account and cancels their own Subscription, s2Member will be notified of these important changes and react accordingly through the PayPal® IPN service that runs silently behind-the-scene. The PayPal® IPN service will notify s2Member whenever a Member\'s payments have been failing ( more than 2 times in a row ), and/or whenever a Member\'s Subscription has expired for any reason. Even refunds &amp; chargeback reversals are supported through the IPN service. If you issue a refund to an unhappy Customer through PayPal®, s2Member will be notified, and the account for that Customer will either be demoted to a Free Subscriber, or deleted automatically ( based on your configuration ). The communication from PayPal® -> s2Member is seamless.</em></p>' . "\n";
111
+ echo '<p><em><strong>*2010 PayPal® Accounts*</strong> s2Member has been updated to support newer PayPal® accounts ( those opened after Oct 15th, 2009 ). Newer PayPal® accounts do NOT send a <strong>IPN</strong>/<code>subscr_eot</code> in all cases. s2Member deals with this gracefully, by keeping a record of payments/periods/changes, and monitoring other signals sent by PayPal® over an extended period. This allows s2Member to take control of the situation at the appropriate time. The communication from PayPal® -> s2Member is seamless; even in PayPal® accounts created after October 15th, 2009. You can learn more about <code>subscr_eot</code> changes <a href="https://www.x.com/search.jspa?q=subscr+eot" target="_blank" rel="external">here</a>.</em></p>' . "\n";
112
  echo '</div>' . "\n";
113
  /**/
114
  echo '</div>' . "\n";
121
  echo '<p>Turn the Auto-Return feature: <strong><code>On</code></strong></p>' . "\n";
122
  echo '<p>You\'ll need your Auto-Return URL, which is:<br /><code>' . get_bloginfo ("url") . '/?s2member_paypal_return=1</code></p>' . "\n";
123
  echo '<p>You MUST also enable PDT ( Payment Data Transfer ): <strong><code>On</code></strong><br /><em>You\'ll be issued an Identity Token that you MUST enter below.</em></p>' . "\n";
124
+ echo '<p><em><strong>*Quick Tip*</strong> In addition to your default PayPal® account configuration, the Auto-Return URL is also set on a per-transaction basis from within the special PayPal® Button Code that s2Member provides you with. In other words, if you have multiple sites operating on one PayPal® account, that\'s OK. s2Member dynamically sets the Auto-Return URL for each transaction. The result is that the Auto-Return URL configured from within your PayPal® account, becomes the default, which is then overwritten on a per transaction basis.</em></p>' . "\n";
125
  /**/
126
  echo '<table class="form-table">' . "\n";
127
  echo '<tbody>' . "\n";
190
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
191
  echo '<ul>' . "\n";
192
  echo '<li><code>%%registration_url%% = The full URL ( generated by s2Member ) where the Customer can get registered.</code></li>' . "\n";
193
+ echo '<li><code>%%subscr_id%% = The PayPal® Subscription ID, which remains constant throughout any &amp; all future payments.</code> [ <a href="#" onclick="alert(\'There is one exception. If you are selling Lifetime or Fixed-Term ( non-recurring ) access, using a Buy It Now button; the %%subscr_id%% is actually set to the Transaction ID for the purchase.\\n\\nPayPal® does not provide a specific Subscription ID for Buy It Now purchases. Since Lifetime &amp; Fixed-Term Subscriptions are NOT recurring ( i.e. there is only ONE payment ), using the Transaction ID as the Subscription ID is a graceful way to deal with this minor conflict.\'); return false;">?</a> ]</li>' . "\n";
194
  echo '<li><code>%%initial%% = The Initial Fee charged during signup. If you offered a free trial, this will be 0.</code> [ <a href="#" onclick="alert(\'This will always represent the amount of money the Customer spent, whenever they initially signed up, no matter what. If a Customer signs up, under the terms of a free trial period, this will be 0.\'); return false;">?</a> ]</li>' . "\n";
195
+ echo '<li><code>%%regular%% = The Regular Amount of the Subscription. This value is always > 0, no matter what.</code> [ <a href="#" onclick="alert(\'This is how much the Subscription costs after an initial period expires. The %%regular%% rate is always > 0. If you did not offer an initial period, %%initial%% and %%regular%% will be equal to the same thing.\'); return false;">?</a> ]</li>' . "\n";
196
+ echo '<li><code>%%recurring%% = This is the amount that will be charged on a Recurring basis, or 0 if non-Recurring.</code> [ <a href="#" onclick="alert(\'If recurring payments have not been required, this will be equal to 0. That being said, %%regular%% &amp; %%recurring%% are usually the same value. This variable can be used in two different ways. You can use it to determine what the regular recurring rate is, or to determine whether the Subscription will recur or not. If it is going to recur, %%recurring%% will be > 0.\\n\\nThe only time this is NOT equal to the %%regular%% rate, is when recurring payments are not required; and only a one-time regular rate applies.\'); return false;">?</a> ]</li>' . "\n";
197
+ echo '<li><code>%%first_name%% = The First Name of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
198
+ echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
199
+ echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased the Membership Subscription.</code></li>' . "\n";
200
+ echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
201
+ echo '<li><code>%%item_number%% = The Item Number ( colon separated <em>level:custom_capabilities:fixed term</em> ) that the Subscription is for.</code></li>' . "\n";
202
  echo '<li><code>%%item_name%% = The Item Name ( in other words, the associated membership Level Label that briefly describes the item number ).</code></li>' . "\n";
203
+ echo '<li><code>%%initial_term%% = This is the term length of the initial period. This will be a numeric value, followed by a space, then a single letter.</code> [ <a href="#" onclick="alert(\'Here are some examples:\\n\\n%%initial_term%% = 1 D ( this means 1 Day )\\n%%initial_term%% = 1 W ( this means 1 Week )\\n%%initial_term%% = 1 M ( this means 1 Month )\\n%%initial_term%% = 1 Y ( this means 1 Year )\\n\\nThe initial period never recurs, so this only lasts for the term length specified, then it is over. If no initial period was even offered, the value of %%initial_term%% will just be: 0 D, meaning zero days.\'); return false;">?</a> ]</li>' . "\n";
204
+ echo '<li><code>%%regular_term%% = This is the term length of the regular period. This will be a numeric value, followed by a space, then a single letter.</code> [ <a href="#" onclick="alert(\'Here are some examples:\\n\\n%%regular_term%% = 1 D ( this means 1 Day )\\n%%regular_term%% = 1 W ( this means 1 Week )\\n%%regular_term%% = 1 M ( this means 1 Month )\\n%%regular_term%% = 1 Y ( this means 1 Year )\\n%%regular_term%% = 1 L ( this means 1 Lifetime )\\n\\nThe regular term is usually recurring. So the regular term value represents the period ( or duration ) of each recurring period. If %%recurring%% = 0, then the regular term only applies once, because it is not recurring. So if it is not recurring, the value of %%regular_term%% simply represents how long their membership privileges are going to last after the %%initial_term%% has expired, if there was an initial term. The value of this variable ( %%regular_term%% ) will never be empty, it will always be at least: 1 D, meaning 1 day. No exceptions.\'); return false;">?</a> ]</li>' . "\n";
205
  echo '</ul>' . "\n";
206
  echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
207
  echo '<ul>' . "\n";
208
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
209
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
210
  echo '</ul>' . "\n";
211
+ echo '<strong>This example uses cv1 to track a User\'s IP address:</strong><br />' . "\n";
212
+ echo '<em>( The IP address could be referenced in your Confirmation Email using %%cv1%% )</em><br />' . "\n";
213
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
214
  echo '</td>' . "\n";
215
  /**/
220
  /**/
221
  echo '</div>' . "\n";
222
  /**/
223
+ echo '<div class="ws-menu-page-group" title="PayPal® Specific Post/Page Email">' . "\n";
224
  /**/
225
+ echo '<div class="ws-menu-page-section ws-plugin--s2member-specific-page-email-section">' . "\n";
226
+ echo '<h3>Specific Post/Page Confirmation Email ( required, but the default works fine )</h3>' . "\n";
227
+ echo '<p>This email is sent to new Customers after they return from a successful purchase at PayPal®, for Specific Post/Page Access. ( see: <code>s2Member -> General Options -> Specific Post/Page Access</code> ). This is NOT used for Membership sales, only for Specific Post/Page Access. The <strong>primary</strong> purpose of this email, is to provide the Customer with instructions, along with a link to access the Specific Post/Page they\'ve purchased access to. If you\'ve created a Specific Post/Page Package ( with multiple Posts/Pages bundled together into one transaction ), this ONE link ( <code>%%sp_access_url%%</code> ) will automatically authenticate them for access to ALL of the Posts/Pages included in their transaction. You may customize this email further, by providing details that are specifically geared to your site.</p>' . "\n";
228
  /**/
229
  echo '<table class="form-table">' . "\n";
230
  echo '<tbody>' . "\n";
231
  echo '<tr>' . "\n";
232
  /**/
233
  echo '<th>' . "\n";
234
+ echo '<label for="ws-plugin--s2member-sp-email-subject">' . "\n";
235
+ echo 'Specific Post/Page Confirmation Email Subject:' . "\n";
236
  echo '</label>' . "\n";
237
  echo '</th>' . "\n";
238
  /**/
240
  echo '<tr>' . "\n";
241
  /**/
242
  echo '<td>' . "\n";
243
+ echo '<input type="text" name="ws_plugin__s2member_sp_email_subject" id="ws-plugin--s2member-sp-email-subject" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_email_subject"]) . '" /><br />' . "\n";
244
+ echo 'Subject Line used in the email sent to a Customer after a successful purchase has occurred through PayPal® for Specific Post/Page Access.' . "\n";
245
  echo '</td>' . "\n";
246
  /**/
247
  echo '</tr>' . "\n";
248
  echo '<tr>' . "\n";
249
  /**/
250
  echo '<th>' . "\n";
251
+ echo '<label for="ws-plugin--s2member-sp-email-message">' . "\n";
252
+ echo 'Specific Post/Page Confirmation Email Message:' . "\n";
253
  echo '</label>' . "\n";
254
  echo '</th>' . "\n";
255
  /**/
257
  echo '<tr>' . "\n";
258
  /**/
259
  echo '<td>' . "\n";
260
+ echo '<textarea name="ws_plugin__s2member_sp_email_message" id="ws-plugin--s2member-sp-email-message" rows="10">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_email_message"]) . '</textarea><br />' . "\n";
261
+ echo 'Message Body used in the email sent to a Customer after a successful purchase has occurred through PayPal® for Specific Post/Page Access.<br /><br />' . "\n";
262
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
263
  echo '<ul>' . "\n";
264
  echo '<li><code>%%sp_access_url%% = The full URL ( generated by s2Member ) where the Customer can gain access.</code></li>' . "\n";
265
  echo '<li><code>%%sp_access_exp%% = Human readable expiration for %%sp_access_url%%. Ex: <em>( link expires in %%sp_access_exp%% )</em>.</code></li>' . "\n";
266
  echo '<li><code>%%txn_id%% = The PayPal® Transaction ID. PayPal® assigns a unique identifier for every purchase.</code></li>' . "\n";
267
+ echo '<li><code>%%amount%% = The full Amount that you charged for Specific Post/Page Access. This value will always be > 0.</code></li>' . "\n";
268
+ echo '<li><code>%%first_name%% = The First Name of the Customer who purchased Specific Post/Page Access through PayPal®.</code></li>' . "\n";
269
+ echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased Specific Post/Page Access through PayPal®.</code></li>' . "\n";
270
+ echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased Specific Post/Page Access.</code></li>' . "\n";
271
+ echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased Specific Post/Page Access through PayPal®.</code></li>' . "\n";
272
+ echo '<li><code>%%item_number%% = The Item Number. Ex: <em>sp:13,24,36:72</em> ( translates to: <em>sp:comma-delimited IDs:expiration hours</em> ).</code></li>' . "\n";
273
  echo '<li><code>%%item_name%% = The Item Name. In other words, a brief description, detailing what this purchase was for.</code></li>' . "\n";
274
  echo '</ul>' . "\n";
275
  echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
277
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
278
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</li>' . "\n";
279
  echo '</ul>' . "\n";
280
+ echo '<strong>This example uses cv1 to track a User\'s IP address:</strong><br />' . "\n";
281
+ echo '<em>( The IP address could be referenced in your Confirmation Email using %%cv1%% )</em><br />' . "\n";
282
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
283
  echo '</td>' . "\n";
284
  /**/
293
  /**/
294
  echo '<div class="ws-menu-page-section ws-plugin--s2member-eot-behavior-section">' . "\n";
295
  echo '<h3>PayPal® EOT Behavior ( required, please choose )</h3>' . "\n";
296
+ echo '<p>EOT = End Of Term. By default, s2Member will demote a paid Member to a Free Subscriber whenever their Subscription term has ended ( i.e. expired ), been cancelled, refunded, charged back to you, etc. s2Member demotes them to a Free Subscriber, so they will no longer have paid Member Level Access to your site. However, in some cases, you may prefer to have Customer accounts deleted completely, instead of just being demoted. This is where you choose which method works best for your site. If you don\'t want s2Member to take ANY action at all, you can disable s2Member\'s EOT System temporarily, or even completely.</p>' . "\n";
297
  echo '<table class="form-table">' . "\n";
298
  echo '<tbody>' . "\n";
299
  echo '<tr>' . "\n";
300
  /**/
301
  echo '<th>' . "\n";
302
+ echo '<label for="ws-plugin--s2member-auto-eot-system-enabled">' . "\n";
303
+ echo 'Enable s2Member\'s Auto-EOT System?' . "\n";
304
+ echo '</label>' . "\n";
305
+ echo '</th>' . "\n";
306
+ /**/
307
+ echo '</tr>' . "\n";
308
+ echo '<tr>' . "\n";
309
+ /**/
310
+ echo '<td>' . "\n";
311
+ echo '<select name="ws_plugin__s2member_auto_eot_system_enabled" id="ws-plugin--s2member-auto-eot-system-enabled">' . "\n";
312
+ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["auto_eot_system_enabled"] && !wp_get_schedule ("s2member_auto_eot_system")) ? '<option value="" selected="selected"></option>' : '';
313
+ echo '<option value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["auto_eot_system_enabled"] && wp_get_schedule ("s2member_auto_eot_system")) ? ' selected="selected"' : '') . '>Yes ( enable the Auto-EOT System through WP_Cron )</option>' . "\n";
314
+ echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["auto_eot_system_enabled"]) ? ' selected="selected"' : '') . '>No ( temporarily disable the Auto-EOT System )</option>' . "\n";
315
+ echo '</select><br />' . "\n";
316
+ echo 'Recommended setting: ( <code>Yes / enable</code> )' . "\n";
317
+ echo '</td>' . "\n";
318
+ /**/
319
+ echo '</tr>' . "\n";
320
+ echo '<tr>' . "\n";
321
+ /**/
322
+ echo '<th>' . "\n";
323
  echo '<label for="ws-plugin--s2member-membership-eot-behavior">' . "\n";
324
  echo 'Membership EOT Behavior ( demote or delete )?' . "\n";
325
  echo '</label>' . "\n";
includes/menu-pages/scripting.inc.php CHANGED
@@ -133,6 +133,11 @@ echo 'You\'ll need to have this plugin installed to use PHP code in Posts/Pages.
133
  /**/
134
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
135
  /**/
 
 
 
 
 
136
  echo '<p><strong>S2MEMBER_CURRENT_USER_IS_LOGGED_IN</strong><br />This will always be (bool) true or false. True if a User/Member is currently logged in with an Access Level >= 0.</p>' . "\n";
137
  echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/current-user-is-logged-in.php"), true) . '</p>' . "\n";
138
  echo '<p><em>See <code>S2MEMBER_CURRENT_USER_ACCESS_LEVEL</code> below for a full explanation.</em></p>' . "\n";
@@ -263,7 +268,7 @@ echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-sa
263
  /**/
264
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
265
  /**/
266
- echo '<p><strong>S2MEMBER_LOGIN_WELCOME_PAGE_URL</strong><br />This is the full URL to the Login Welcome Page ( the user\'s account page ). * This could also be the full URL to a Special Redirection URL ( if you configured one ). See <code>s2Member -> General Options -> Login Welcome Page</code>.</p>' . "\n";
267
  echo '<p><strong>S2MEMBER_LOGIN_WELCOME_PAGE_ID</strong><br />This is the Page ID that was used to generate the full URL. * In the case of a Special Redirection URL, this ID is not really applicable.</p>' . "\n";
268
  echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/login-welcome-page-url.php"), true) . '</p>' . "\n";
269
  /**/
@@ -380,7 +385,7 @@ echo '<p>These two Constants are special. They are used by the PayPal® Button G
380
  echo '<p><em>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/current-user-value-for-pp-on0-os0.php"), true) . '</em></p>' . "\n";
381
  echo '<p>If you\'d like to give your Members ( and/or your Free Subscribers ) the ability to modify their billing plan, by switching to a more expensive option, or a less expensive option; generate a new PayPal® Modification Button, using the s2Member PayPal® Button Generator. Configure the updated Level, pricing, terms, etc. Then, make that new Modification Button available to Members who are logged into their existing account with you. For example, you might want to insert a "Level #2" Upgrade Button into your Login Welcome Page, which would up-sell existing Level #1 Members to a more expensive plan that you offer.</p>' . "\n";
382
  echo '<p><em><strong>*Modification Process*</strong> When you send a Member to PayPal® using a Subscription Modification Button, PayPal® will ask them to login. Once they\'re logged in, instead of being able to signup for a new membership, PayPal® will provide them with the ability to upgrade and/or downgrade their existing membership with you, by allowing them to switch to the Membership Plan that was specified in the Subscription Modification Button. PayPal® handles this nicely, and you\'ll be happy to know that s2Member has been pre-configured to deal with this scenario as well, so that everything remains automated. Their Membership Access Level will either be promoted, or demoted, based on the actions they took at PayPal® during the modification process. Once an existing Member completes their Subscription Modification at PayPal®, they\'ll be brought back to their Login Welcome Page, instead of the registration screen.</em></p>' . "\n";
383
- echo '<p><em><strong>*Also Works For Free Subscribers*</strong> Although a Free Subscriber does not have an existing PayPal® subscription, s2Member is capable of adapting to this scenario gracefully. Just make sure that your existing Free Subscribers ( the ones who wish to upgrade ) pay for their Membership through a Modification Button generated by s2Member. That will allow them to continue using their existing account with you. In other words, they can keep their existing Username ( and anything already associated with that Username ), rather than being forced to re-register after checkout.</em></p>' . "\n";
384
  echo '<p><em><strong>*Make It More User-Friendly*</strong> You can make the Subscription Modification Process, more user-friendly, by setting up a <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can tell s2Member to use that Page Style whenever you generate your Button Code. See: s2Member® -> PayPal Buttons.\'); return false;">Custom Page Style at PayPal®</a>, specifically for Subscription Modification Buttons. Use a custom header image, with a brief explanation to the Customer. Something like, "Log into PayPal®", "You can Modify your Subscription!".</em></p>' . "\n";
385
  echo '<p><em><strong>*Conditional Upgrades*</strong> You could also use the API Constant <code>S2MEMBER_CURRENT_USER_ACCESS_LEVEL</code> to build Conditionals that display a specific Modification Button, based on the Membership Level of the currently logged-in Member. This can help you maximize your marketing efforts. In other words, instead of just throwing a single Modification Button out there to everyone, get specific if you need to!</em></p>' . "\n";
386
  echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/current-user-access-level-conditional-upgrades.php"), true) . '</p>' . "\n";
133
  /**/
134
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
135
  /**/
136
+ echo '<p><strong>S2MEMBER_VERSION</strong><br />This will always be a (string) with the current s2Member version. Available since s2Member 3.0.</p>' . "\n";
137
+ echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/version.php"), true) . '</p>' . "\n";
138
+ /**/
139
+ echo '<div class="ws-menu-page-hr"></div>' . "\n";
140
+ /**/
141
  echo '<p><strong>S2MEMBER_CURRENT_USER_IS_LOGGED_IN</strong><br />This will always be (bool) true or false. True if a User/Member is currently logged in with an Access Level >= 0.</p>' . "\n";
142
  echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/current-user-is-logged-in.php"), true) . '</p>' . "\n";
143
  echo '<p><em>See <code>S2MEMBER_CURRENT_USER_ACCESS_LEVEL</code> below for a full explanation.</em></p>' . "\n";
268
  /**/
269
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
270
  /**/
271
+ echo '<p><strong>S2MEMBER_LOGIN_WELCOME_PAGE_URL</strong><br />This is the full URL to the Login Welcome Page ( the User\'s account page ). * This could also be the full URL to a Special Redirection URL ( if you configured one ). See <code>s2Member -> General Options -> Login Welcome Page</code>.</p>' . "\n";
272
  echo '<p><strong>S2MEMBER_LOGIN_WELCOME_PAGE_ID</strong><br />This is the Page ID that was used to generate the full URL. * In the case of a Special Redirection URL, this ID is not really applicable.</p>' . "\n";
273
  echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/login-welcome-page-url.php"), true) . '</p>' . "\n";
274
  /**/
385
  echo '<p><em>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/current-user-value-for-pp-on0-os0.php"), true) . '</em></p>' . "\n";
386
  echo '<p>If you\'d like to give your Members ( and/or your Free Subscribers ) the ability to modify their billing plan, by switching to a more expensive option, or a less expensive option; generate a new PayPal® Modification Button, using the s2Member PayPal® Button Generator. Configure the updated Level, pricing, terms, etc. Then, make that new Modification Button available to Members who are logged into their existing account with you. For example, you might want to insert a "Level #2" Upgrade Button into your Login Welcome Page, which would up-sell existing Level #1 Members to a more expensive plan that you offer.</p>' . "\n";
387
  echo '<p><em><strong>*Modification Process*</strong> When you send a Member to PayPal® using a Subscription Modification Button, PayPal® will ask them to login. Once they\'re logged in, instead of being able to signup for a new membership, PayPal® will provide them with the ability to upgrade and/or downgrade their existing membership with you, by allowing them to switch to the Membership Plan that was specified in the Subscription Modification Button. PayPal® handles this nicely, and you\'ll be happy to know that s2Member has been pre-configured to deal with this scenario as well, so that everything remains automated. Their Membership Access Level will either be promoted, or demoted, based on the actions they took at PayPal® during the modification process. Once an existing Member completes their Subscription Modification at PayPal®, they\'ll be brought back to their Login Welcome Page, instead of the registration screen.</em></p>' . "\n";
388
+ echo '<p><em><strong>*Also Works For Free Subscribers*</strong> Although a Free Subscriber does not have an existing PayPal® Subscription, s2Member is capable of adapting to this scenario gracefully. Just make sure that your existing Free Subscribers ( the ones who wish to upgrade ) pay for their Membership through a Modification Button generated by s2Member. That will allow them to continue using their existing account with you. In other words, they can keep their existing Username ( and anything already associated with that Username ), rather than being forced to re-register after checkout.</em></p>' . "\n";
389
  echo '<p><em><strong>*Make It More User-Friendly*</strong> You can make the Subscription Modification Process, more user-friendly, by setting up a <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can tell s2Member to use that Page Style whenever you generate your Button Code. See: s2Member® -> PayPal Buttons.\'); return false;">Custom Page Style at PayPal®</a>, specifically for Subscription Modification Buttons. Use a custom header image, with a brief explanation to the Customer. Something like, "Log into PayPal®", "You can Modify your Subscription!".</em></p>' . "\n";
390
  echo '<p><em><strong>*Conditional Upgrades*</strong> You could also use the API Constant <code>S2MEMBER_CURRENT_USER_ACCESS_LEVEL</code> to build Conditionals that display a specific Modification Button, based on the Membership Level of the currently logged-in Member. This can help you maximize your marketing efforts. In other words, instead of just throwing a single Modification Button out there to everyone, get specific if you need to!</em></p>' . "\n";
391
  echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/current-user-access-level-conditional-upgrades.php"), true) . '</p>' . "\n";
includes/menu-pages/start.inc.php CHANGED
@@ -83,16 +83,10 @@ echo '<div class="ws-menu-page-group" title="Subscription Cancellations">' . "\n
83
  /**/
84
  echo '<div class="ws-menu-page-section ws-plugin--s2member-automation-process-section">' . "\n";
85
  echo '<h3>Subscription Cancellations / Expirations / Terminations</h3>' . "\n";
86
- echo '<p>You\'ll be happy to know that s2Member handles cancellations, expirations, failed payments ( more than 2 in a row ), terminations ( e.g. refunds &amp; chargebacks ) for you automatically. If you log into your PayPal® account and cancel a Member\'s subscription, or, if the Member logs into their PayPal® account and cancels their own subscription, s2Member will be notified of these important changes and react accordingly through the PayPal® IPN service that runs silently behind-the-scene.</p>' . "\n";
87
- echo '<p>The PayPal® IPN service will notify s2Member whenever a Member\'s payments have been failing ( more than 2 times in a row ), and/or whenever a Member\'s subscription has expired for any reason. Even refunds &amp; chargeback reversals are supported through the IPN service. If you issue a refund to an unhappy Customer through PayPal®, s2Member will be notified, and the account for that Customer will either be demoted to a Free Subscriber, or deleted automatically ( based on your configuration ). The communication from PayPal® -> s2Member is seamless.</p>' . "\n";
88
- echo '<p>You may also want to check the s2Member API Notifications panel. You\'ll find additional layers of automation available through the use of the `Signup`, `Registration`, `Payment`, `EOT/Deletion`, `Refund/Reversal`, and `Single-Page` notifications that are available to you through the s2Member API. These make it possible to integrate with 3rd party applications; like affiliate programs, list servers, and other back-office routines.</p>' . "\n";
89
- echo '</div>' . "\n";
90
- /**/
91
- echo '<div class="ws-menu-page-hr ws-plugin--s2member-automation-hairy-details-section-hr"></div>' . "\n";
92
- /**/
93
- echo '<div class="ws-menu-page-section ws-plugin--s2member-automation-hairy-details-section">' . "\n";
94
- echo '<h3>Subscription Cancellations / Some Hairy Details With Dates</h3>' . "\n";
95
- echo '<p>There might be times whenever you notice that a Members\'s subscription has been canceled through PayPal®... but, s2Member continues to allow the User to access your site as a paid Member. Please don\'t be confused by this... in 99.9% of these cases, the reason for this is legitimate. s2Member will only remove the User\'s membership privileges when PayPal® sends the SUBSCR_EOT notification via the IPN service. PayPal® will sometimes wait to send this SUBSCR_EOT notification until the User has completely used up the time they paid for. In other words, if a User signs up for a monthly subscription on Jan 1st, and then cancels their subscription on Jan 15th; technically, they should still be allowed to access the site for another 15 days, and then on Feb 1st, the time they paid for has completely elapsed, and PayPal® will send the SUBSCR_EOT notification to s2Member. At that time, s2Member will remove their membership privileges; by either demoting them to a Free Subscriber, or deleting their account from the system ( based on your configuration ).</p>' . "\n";
96
  echo '</div>' . "\n";
97
  /**/
98
  echo '</div>' . "\n";
@@ -112,7 +106,7 @@ echo '<div class="ws-menu-page-section ws-plugin--s2member-subscription-modifica
112
  echo '<h3>Giving Members The Ability To Modify Their Own Subscription</h3>' . "\n";
113
  echo '<p>If you\'d like to give your Members ( and/or your Free Subscribers ) the ability to modify their billing plan, by switching to a more expensive option, or a less expensive option; generate a new PayPal® Modification Button, using the s2Member PayPal® Button Generator. Configure the updated Level, pricing, terms, etc. Then, make that new Modification Button available to Members who are logged into their existing account with you. For example, you might want to insert a "Level #2" Upgrade Button into your Login Welcome Page, which would up-sell existing Level #1 Members to a more expensive plan that you offer.</p>' . "\n";
114
  echo '<p><em><strong>*Modification Process*</strong> When you send a Member to PayPal® using a Subscription Modification Button, PayPal® will ask them to login. Once they\'re logged in, instead of being able to signup for a new membership, PayPal® will provide them with the ability to upgrade and/or downgrade their existing membership with you, by allowing them to switch to the Membership Plan that was specified in the Subscription Modification Button. PayPal® handles this nicely, and you\'ll be happy to know that s2Member has been pre-configured to deal with this scenario as well, so that everything remains automated. Their Membership Access Level will either be promoted, or demoted, based on the actions they took at PayPal® during the modification process. Once an existing Member completes their Subscription Modification at PayPal®, they\'ll be brought back to their Login Welcome Page, instead of the registration screen.</em></p>' . "\n";
115
- echo '<p><em><strong>*Also Works For Free Subscribers*</strong> Although a Free Subscriber does not have an existing PayPal® subscription, s2Member is capable of adapting to this scenario gracefully. Just make sure that your existing Free Subscribers ( the ones who wish to upgrade ) pay for their Membership through a Modification Button generated by s2Member. That will allow them to continue using their existing account with you. In other words, they can keep their existing Username ( and anything already associated with that Username ), rather than being forced to re-register after checkout.</em></p>' . "\n";
116
  echo '<p><em><strong>*Make It More User-Friendly*</strong> You can make the Subscription Modification Process, more user-friendly, by setting up a <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can tell s2Member to use that Page Style whenever you generate your Button Code. See: s2Member® -> PayPal Buttons.\'); return false;">Custom Page Style at PayPal®</a>, specifically for Subscription Modification Buttons. Use a custom header image, with a brief explanation to the Customer. Something like, "Log into PayPal®", "You can Modify your Subscription!".</em></p>' . "\n";
117
  echo '</div>' . "\n";
118
  /**/
@@ -120,7 +114,7 @@ echo '<div class="ws-menu-page-hr ws-plugin--s2member-subscription-modification-
120
  /**/
121
  echo '<div class="ws-menu-page-section ws-plugin--s2member-subscription-modification-section">' . "\n";
122
  echo '<h3>Upgrading Free Subscribers To Paid Members ( same technique )</h3>' . "\n";
123
- echo '<p>Same technique as above. This also works for Free Subscribers. Although a Free Subscriber does not have an existing PayPal® subscription, s2Member is capable of adapting to this scenario gracefully. Just make sure that your existing Free Subscribers ( the ones who wish to upgrade ) pay for their Membership through a Modification Button generated by s2Member. That will allow them to continue using their existing account with you. In other words, they can keep their existing Username ( and anything already associated with that Username ), rather than being forced to re-register after checkout.</p>' . "\n";
124
  echo '</div>' . "\n";
125
  /**/
126
  echo '</div>' . "\n";
83
  /**/
84
  echo '<div class="ws-menu-page-section ws-plugin--s2member-automation-process-section">' . "\n";
85
  echo '<h3>Subscription Cancellations / Expirations / Terminations</h3>' . "\n";
86
+ echo '<p>You\'ll be happy to know that s2Member handles cancellations, expirations, failed payments ( more than 2 in a row ), terminations ( e.g. refunds &amp; chargebacks ) for you automatically. If you log into your PayPal® account and cancel a Member\'s Subscription, or, if the Member logs into their PayPal® account and cancels their own Subscription, s2Member will be notified of these important changes and react accordingly through the PayPal® IPN service that runs silently behind-the-scene.</p>' . "\n";
87
+ echo '<p>The PayPal® IPN service will notify s2Member whenever a Member\'s payments have been failing ( more than 2 times in a row ), and/or whenever a Member\'s Subscription has expired for any reason. Even refunds &amp; chargeback reversals are supported through the IPN service. If you issue a refund to an unhappy Customer through PayPal®, s2Member will be notified, and the account for that Customer will either be demoted to a Free Subscriber, or deleted automatically ( based on your configuration ). The communication from PayPal® -> s2Member is seamless.</p>' . "\n";
88
+ echo '<p><em><strong>*Some Hairy Details*</strong> There might be times whenever you notice that a Members\'s Subscription has been cancelled through PayPal®... but, s2Member continues allowing the User access to your site as a paid Member. Please don\'t be confused by this... in 99.9% of these cases, the reason for this is legitimate. s2Member will only remove the User\'s membership privileges when PayPal® sends a <code>subscr_eot</code> notification via the IPN service, a refund occurs, a chargeback occurs, or when a cancellation occurs - which would later result in a delayed Auto-EOT by s2Member. s2Member will not process an EOT until the User has completely used up the time they paid for. In other words, if a User signs up for a monthly Subscription on Jan 1st, and then cancels their Subscription on Jan 15th; technically, they should still be allowed to access the site for another 15 days, and then on Feb 1st, the time they paid for has completely elapsed. At that time, s2Member will remove their membership privileges; by either demoting them to a Free Subscriber, or deleting their account from the system ( based on your configuration ). s2Member also calculates one extra day ( 24 hours ) into its equation, just to make sure access is not removed sooner than a Customer might expect.</em></p>' . "\n";
89
+ echo '<p><em><strong>*2010 PayPal® Accounts*</strong> s2Member has been updated to support newer PayPal® accounts ( those opened after Oct 15th, 2009 ). Newer PayPal® accounts do NOT send an <strong>IPN</strong>/<code>subscr_eot</code> in all cases. s2Member deals with this gracefully, by keeping a record of payments/periods/changes, and monitoring other signals sent by PayPal® over an extended period. This allows s2Member to take control of the situation at the appropriate time, using s2Member\'s built-in Auto-EOT System. The communication from PayPal® -> s2Member is seamless; even in PayPal® accounts created after October 15th, 2009. You can learn more about <code>subscr_eot</code> changes <a href="https://www.x.com/search.jspa?q=subscr+eot" target="_blank" rel="external">here</a>.</em></p>' . "\n";
 
 
 
 
 
 
90
  echo '</div>' . "\n";
91
  /**/
92
  echo '</div>' . "\n";
106
  echo '<h3>Giving Members The Ability To Modify Their Own Subscription</h3>' . "\n";
107
  echo '<p>If you\'d like to give your Members ( and/or your Free Subscribers ) the ability to modify their billing plan, by switching to a more expensive option, or a less expensive option; generate a new PayPal® Modification Button, using the s2Member PayPal® Button Generator. Configure the updated Level, pricing, terms, etc. Then, make that new Modification Button available to Members who are logged into their existing account with you. For example, you might want to insert a "Level #2" Upgrade Button into your Login Welcome Page, which would up-sell existing Level #1 Members to a more expensive plan that you offer.</p>' . "\n";
108
  echo '<p><em><strong>*Modification Process*</strong> When you send a Member to PayPal® using a Subscription Modification Button, PayPal® will ask them to login. Once they\'re logged in, instead of being able to signup for a new membership, PayPal® will provide them with the ability to upgrade and/or downgrade their existing membership with you, by allowing them to switch to the Membership Plan that was specified in the Subscription Modification Button. PayPal® handles this nicely, and you\'ll be happy to know that s2Member has been pre-configured to deal with this scenario as well, so that everything remains automated. Their Membership Access Level will either be promoted, or demoted, based on the actions they took at PayPal® during the modification process. Once an existing Member completes their Subscription Modification at PayPal®, they\'ll be brought back to their Login Welcome Page, instead of the registration screen.</em></p>' . "\n";
109
+ echo '<p><em><strong>*Also Works For Free Subscribers*</strong> Although a Free Subscriber does not have an existing PayPal® Subscription, s2Member is capable of adapting to this scenario gracefully. Just make sure that your existing Free Subscribers ( the ones who wish to upgrade ) pay for their Membership through a Modification Button generated by s2Member. That will allow them to continue using their existing account with you. In other words, they can keep their existing Username ( and anything already associated with that Username ), rather than being forced to re-register after checkout.</em></p>' . "\n";
110
  echo '<p><em><strong>*Make It More User-Friendly*</strong> You can make the Subscription Modification Process, more user-friendly, by setting up a <a href="#" onclick="alert(\'Optional. This can be configured inside your PayPal® account. PayPal® allows you to create Custom Page Styles, and assign a unique name to them. You can add your own header image and color selection to the checkout form. Once you\\\'ve created a Custom Page Style at PayPal®, you can tell s2Member to use that Page Style whenever you generate your Button Code. See: s2Member® -> PayPal Buttons.\'); return false;">Custom Page Style at PayPal®</a>, specifically for Subscription Modification Buttons. Use a custom header image, with a brief explanation to the Customer. Something like, "Log into PayPal®", "You can Modify your Subscription!".</em></p>' . "\n";
111
  echo '</div>' . "\n";
112
  /**/
114
  /**/
115
  echo '<div class="ws-menu-page-section ws-plugin--s2member-subscription-modification-section">' . "\n";
116
  echo '<h3>Upgrading Free Subscribers To Paid Members ( same technique )</h3>' . "\n";
117
+ echo '<p>Same technique as above. This also works for Free Subscribers. Although a Free Subscriber does not have an existing PayPal® Subscription, s2Member is capable of adapting to this scenario gracefully. Just make sure that your existing Free Subscribers ( the ones who wish to upgrade ) pay for their Membership through a Modification Button generated by s2Member. That will allow them to continue using their existing account with you. In other words, they can keep their existing Username ( and anything already associated with that Username ), rather than being forced to re-register after checkout.</p>' . "\n";
118
  echo '</div>' . "\n";
119
  /**/
120
  echo '</div>' . "\n";
includes/menu-pages/trk-ops.inc.php CHANGED
@@ -32,20 +32,19 @@ echo '<form method="post" name="ws_plugin__s2member_options_form" id="ws-plugin-
32
  echo '<input type="hidden" name="ws_plugin__s2member_options_save" id="ws-plugin--s2member-options-save" value="' . esc_attr (wp_create_nonce ("ws-plugin--s2member-options-save")) . '" />' . "\n";
33
  echo '<input type="hidden" name="ws_plugin__s2member_configured" id="ws-plugin--s2member-configured" value="1" />' . "\n";
34
  /**/
35
- echo '<div class="ws-menu-page-group" title="Integrate Custom Tracking Codes">' . "\n";
36
- /**/
37
- echo '<div class="ws-menu-page-section ws-plugin--s2member-tracking-section">' . "\n";
38
- echo '<h3>Tracking Codes ( optional, these will be injected into the Signup Confirmation Page )</h3>' . "\n";
39
- echo '<p>If you use affiliate software, a list server, tracking codes from advertising networks, or the like; you\'ll want to read this section. The HTML' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["is_wpmu"]) ? ' and/or PHP' : '') . ' code that you enter below, will be loaded up in a web browser, whenever a Customer lands on the Signup Confirmation Page after checkout. The s2Member (built-in) Signup Confirmation Page ( also known as a Thank-You Page ), is really just a blank page that alerts the Customer via JavaScript. It says: <em>`Thank You! Your account has been approved.`</em>. Then it says: <em>`The next step is to Register a Username. Please click OK to be redirected.`</em>. After they\'ve clicked OK on this alert, and after everything ( if there is anything ) on the blank page has finished loading, they\'ll be redirected to the registration system, where they will be able to setup their Username and login for the first time. This process has been fully automated, very simple.</p>' . "\n";
40
- echo '<p>Now, if you want to track the performance of your marketing efforts using Google® Analytics, affiliate software or advertising networks, you can place the code for those in the field below. All of the code in the field below, will be injected into the Signup Confirmation Page, between the <code>&lt;body&gt;&lt;/body&gt;</code> tags. After everything in your code has finished loading, the new Member will be redirected to the registration system, so they can setup their Username and login. In other words, the Signup Confirmation Page ensures that all 1x1 pixel images and/or other data from your Tracking Codes ( in the field below ) has finished loading, before it redirects the Member away from the page. This way you can be sure that all of your tracking statistics, and other marketing efforts, remain accurate. This is handled through the magic of the <code>window.onload</code> event, compatible in all major browsers.</p>' . "\n";
41
  /**/
 
 
 
 
42
  echo '<table class="form-table">' . "\n";
43
  echo '<tbody>' . "\n";
44
  echo '<tr>' . "\n";
45
  /**/
46
  echo '<th>' . "\n";
47
  echo '<label for="ws-plugin--s2member-signup-tracking-codes">' . "\n";
48
- echo 'Integrate Custom Tracking Codes:' . "\n";
49
  echo '</label>' . "\n";
50
  echo '</th>' . "\n";
51
  /**/
@@ -54,25 +53,78 @@ echo '<tr>' . "\n";
54
  /**/
55
  echo '<td>' . "\n";
56
  echo '<textarea name="ws_plugin__s2member_signup_tracking_codes" id="ws-plugin--s2member-signup-tracking-codes" rows="8" wrap="off" spellcheck="false" style="font-family:Consolas, monospace;">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_tracking_codes"]) . '</textarea><br />' . "\n";
57
- echo 'Any valid XHTML / JavaScript' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["is_wpmu"]) ? ' ( or even PHP )' : '') . ' code will work just fine here. Just try not to put anything here that would actually be visible to the user. They won\'t see it anyway, because they\'re going to be redirected as soon as it loads up. Things like 1x1 pixel images that load up silently and/or JavaScript tracking routines will be fine. Google® Analytics code works just fine, AdSense® performance tracking, as well as Yahoo® tracking and other affiliate network codes are all OK here.<br /><br />' . "\n";
58
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
59
  echo '<ul>' . "\n";
60
- echo '<li><code>%%subscr_id%% = The PayPal® Subscription ID, which remains constant throughout any &amp; all future payments.</code> [ <a href="#" onclick="alert(\'There is one exception. If you are selling Lifetime ( non-recurring ) access, using a Buy It Now button; the %%subscr_id%% is actually set to the Transaction ID for the purchase.\\n\\nPayPal® does not provide a specific Subscription ID for Buy It Now purchases. Since Lifetime subscriptions are NOT recurring ( i.e. there is only ONE payment ), using the Transaction ID as the Subscription ID is a graceful way to deal with this minor conflict.\'); return false;">?</a> ]</li>' . "\n";
61
- echo '<li><code>%%initial%% = The Initial Fee charged during signup. If you offered a free trial, this will be 0.</code> [ <a href="#" onclick="alert(\'This will always represent the amount of money the Customer spent, whenever they initially signed up, no matter what. Even if that amount is 0.\\n\\nIf a Customer signs up, under the terms of a free trial period, this will be 0. So be careful using %%initial%% when you offer a free trial period, because a $0.00 sale amount could cause havoc with affiliate programs. If you\\\'re offering a free trial period, and you need to track sales through affiliate programs, you can either hard-code an amount into your Tracking Code; or use the more advanced `Payment Notifications`. See: `s2Member -> API Notifications`.\'); return false;">?</a> ]</li>' . "\n";
62
- echo '<li><code>%%first_name%% = The First Name of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
63
- echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
64
- echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased the membership subscription.</code></li>' . "\n";
65
- echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased the membership subscription through PayPal®.</code></li>' . "\n";
66
- echo '<li><code>%%item_number%% = The Item Number ( colon separated <em>level:custom_capabilities</em> ) that the subscription is for.</code></li>' . "\n";
67
- echo '<li><code>%%item_name%% = The Item Name ( in other words, the associated membership Level Label that briefly describes the item number ).</code></li>' . "\n";
 
 
 
 
68
  echo '</ul>' . "\n";
69
  echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
70
  echo '<ul>' . "\n";
71
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
72
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</code></li>' . "\n";
73
  echo '</ul>' . "\n";
74
- echo '<strong>This example uses cv1 to track a user\'s IP address:</strong><br />' . "\n";
75
- echo '<em>( The IP address can be referenced in your Tracking Code using %%cv1%% )</em><br />' . "\n";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
77
  echo '</td>' . "\n";
78
  /**/
@@ -89,8 +141,12 @@ echo '<div class="ws-menu-page-section ws-plugin--s2member-idev-section">' . "\n
89
  echo '<h3>Integrating iDevAffiliate® ( affiliate program management )</h3>' . "\n";
90
  echo '<a href="http://www.idevdirect.com/14200.html" target="_blank"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/idev-logo.gif" class="ws-menu-page-right" style="width:125px; height:125px; border:0;" alt="." /></a>' . "\n";
91
  echo '<p>Adding affiliate tracking software to your site is one of the most effective ways to achieve more sales, more traffic, and more search engine ranking. <a href="http://www.idevdirect.com/14200.html" target="_blank" rel="external">iDevAffiliate®</a> ( an affiliate management portal ), installs in just minutes, and can be integrated seamlessly with s2Member. We recommend <a href="http://www.idevdirect.com/14200.html" target="_blank" rel="external">iDevAffiliate® Standard</a> ( $99 ) because of its proven track record, and its ability to integrate with s2Member using a variety of techniques. The most popular being a Hidden Image Tag.</p>' . "\n";
92
- echo '<p>If you choose to <a href="http://www.idevdirect.com/14200.html" target="_blank" rel="external">install iDevAffiliate®</a>, you will need to configure your <code>iDevAffiliate® -> Shopping Cart Integration</code>. Please choose <code>Generic Tracking Pixel</code>. Then, grab your Hidden Image Tag, and pop the code provided by iDevAffiliate® into the Custom Tracking field at the top of this page. You MUST also add replacement codes to your Hidden Image Tag. To save you some trouble, we\'ve provided an example below. These are the two variables that iDevAffiliate® needs.</p>' . "\n";
 
93
  echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/idev-signup-tracking-code.php"), true) . '</p>' . "\n";
 
 
 
94
  echo '<p>Your <code>profile</code> ID will be assigned by iDevAffiliate®. Be sure to replace <code>profile=123</code> with your own profile ID.</p>' . "\n";
95
  echo '<p><em><strong>*Tip*</strong> iDevAffiliate® also provides an alternative method, using a 3rd-party call. The alternative 3rd-party call, could be used with <code>s2Member -> API Notifications.</code> A 3rd-party call, is essentially an HTTP connection that runs silently behind-the-scene, as opposed to being loaded in a browser. It\'s a bit more powerful, but also more advanced.</em></p>' . "\n";
96
  echo '</div>' . "\n";
@@ -103,28 +159,23 @@ echo '<div class="ws-menu-page-section ws-plugin--s2member-shareasale-section">'
103
  echo '<h3>Integrating ShareASale® ( affiliate program management )</h3>' . "\n";
104
  echo '<a href="http://www.shareasale.com/merchantsignup.cfm" target="_blank"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/sas-logo.png" class="ws-menu-page-right" style="width:125px; height:125px; border:0;" alt="." /></a>' . "\n";
105
  echo '<p>Established in 2000, <a href="http://www.shareasale.com/merchantsignup.cfm" target="_blank" rel="external">ShareASale®</a> provides award winning technology and service; which will enable you to connect with a network of established affiliates, as well as recruit new ones. Joining ShareASale®, maximizes your ability to reach the greatest number of affiliates, with the least amount of work. At ShareASale®, you\'ll have access to an existing affiliate-base. You place your site on the market, and let their existing affiliates promote your products/services.</p>' . "\n";
106
- echo '<p>If you <a href="http://www.shareasale.com/merchantsignup.cfm" target="_blank" rel="external">become a Merchant at ShareASale®</a>, you will need to configure your <code>ShareASale® -> Sale Tracking</code>. Grab your Hidden Image Tag, and pop the code provided by ShareASale® into the Custom Tracking field at the top of this page. You MUST also add replacement codes to your Hidden Image Tag. To save you some trouble, we\'ve provided an example below. These are the two variables that ShareASale® needs.</p>' . "\n";
 
107
  echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/sas-signup-tracking-code.php"), true) . '</p>' . "\n";
 
 
 
108
  echo '<p>Your <code>merchantID</code> will be assigned by ShareASale®. Be sure to replace <code>merchantID=123</code> with the one they assign you.</p>' . "\n";
109
  echo '<p><em><strong>*Tip*</strong> ShareASale® also provides an alternative method, using a 3rd-party call. The alternative 3rd-party call, could be used with <code>s2Member -> API Notifications.</code> A 3rd-party call, is essentially an HTTP connection that runs silently behind-the-scene, as opposed to being loaded in a browser. It\'s a bit more powerful, but also more advanced.</em></p>' . "\n";
110
  echo '</div>' . "\n";
111
  /**/
112
  echo '</div>' . "\n";
113
  /**/
114
- echo '<div class="ws-menu-page-group" title="Tracking Single-Page Access">' . "\n";
115
- /**/
116
- echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-access-section">' . "\n";
117
- echo '<h3>Tracking Single-Page Access ( this is different )</h3>' . "\n";
118
- echo '<p>Single-Page Access works independently from Member Level Access. For full details, see: <code>s2Member -> General Options -> Single-Page Access</code>. If you need to track Single-Page Access, you will need to insert separate Tracking Codes yourself, on a Page-by-Page basis; into each Page you\'re selling access to. The Signup Confirmation Page is NOT loaded for Single-Page transactions. Instead, Customers are immediately redirected to the Page you sold them access to. Again, just to be clear... The Signup Confirmation Page ( and the Custom Tracking Codes in the section above ) are NOT injected for Single-Page Access, only for Member Level Access.</p>' . "\n";
119
- echo '</div>' . "\n";
120
- /**/
121
- echo '</div>' . "\n";
122
- /**/
123
  echo '<div class="ws-menu-page-group" title="Other Tracking Methods Available">' . "\n";
124
  /**/
125
  echo '<div class="ws-menu-page-section ws-plugin--s2member-other-methods-section">' . "\n";
126
  echo '<h3>Other Tracking Methods Are Available ( there\'s always a way )</h3>' . "\n";
127
- echo '<p>Check the s2Member API Notifications panel. You\'ll find additional layers of automation available through the use of the `Signup`, `Registration`, `Payment`, `EOT/Deletion`, `Refund/Reversal`, and `Single-Page` notifications that are available to you through the s2Member API. The s2Member API Notifications make it possible to integrate with 3rd party applications; like list servers, affiliate programs, and other back-office routines; in more advanced ways. Since the s2Member API Notifications operate silently on the back-end, in conjunction with the PayPal® IPN system, they tend to be more reliable and also more versatile. That being said, nothing replaces the simplicity of Tracking Codes. The more advanced API Notifications are NOT always the best tool for the job. For instance, API Notifications will NOT work with Google® Analytics, or 1 pixel &lt;img&gt; tags. They operate silently behind-the-scene, using cURL connections, as opposed to being loaded in a browser.</p>' . "\n";
128
  echo '</div>' . "\n";
129
  /**/
130
  echo '</div>' . "\n";
32
  echo '<input type="hidden" name="ws_plugin__s2member_options_save" id="ws-plugin--s2member-options-save" value="' . esc_attr (wp_create_nonce ("ws-plugin--s2member-options-save")) . '" />' . "\n";
33
  echo '<input type="hidden" name="ws_plugin__s2member_configured" id="ws-plugin--s2member-configured" value="1" />' . "\n";
34
  /**/
35
+ echo '<div class="ws-menu-page-group" title="Membership Signup Tracking Codes">' . "\n";
 
 
 
 
 
36
  /**/
37
+ echo '<div class="ws-menu-page-section ws-plugin--s2member-signup-tracking-section">' . "\n";
38
+ echo '<h3>Membership Signup Tracking Codes ( optional )</h3>' . "\n";
39
+ echo '<p>If you use affiliate software, a list server, tracking codes from advertising networks, or the like; you\'ll want to read this section. The HTML' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["is_wpmu_farm"]) ? ' and/or PHP' : '') . ' code that you enter below, will be loaded up in a web browser, after a Customer returns from a successful Signup through PayPal®. Tracking Codes are only displayed/processed one time for each Customer. s2Member will display your Tracking Codes in one of three possible locations... <strong>1.</strong> If possible, on the Registration Form, after returning from PayPal®. <strong>2.</strong> Otherwise, if possible, on the Login Form after Registration is completed. <strong>3.</strong> Otherwise, in the footer of your WordPress® theme, after the Customer\'s very first Login.</p>' . "\n";
40
+ echo '<p>Signup Tracking Codes are displayed for all types of Membership Level Access. Including: Recurring Subscriptions ( with or without a free trial period ), Non-Recurring Subscriptions ( with or without a free trial period ), Lifetime Subscriptions, and even Fixed-Term Subscriptions. All of these are supported by s2Member\'s Button Generator, and all of these are supported here.</p>' . "\n";
41
  echo '<table class="form-table">' . "\n";
42
  echo '<tbody>' . "\n";
43
  echo '<tr>' . "\n";
44
  /**/
45
  echo '<th>' . "\n";
46
  echo '<label for="ws-plugin--s2member-signup-tracking-codes">' . "\n";
47
+ echo 'Integrate Signup Tracking Codes:' . "\n";
48
  echo '</label>' . "\n";
49
  echo '</th>' . "\n";
50
  /**/
53
  /**/
54
  echo '<td>' . "\n";
55
  echo '<textarea name="ws_plugin__s2member_signup_tracking_codes" id="ws-plugin--s2member-signup-tracking-codes" rows="8" wrap="off" spellcheck="false" style="font-family:Consolas, monospace;">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_tracking_codes"]) . '</textarea><br />' . "\n";
56
+ echo 'Any valid XHTML / JavaScript' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["is_wpmu_farm"]) ? ' ( or even PHP )' : '') . ' code will work just fine here. Just try not to put anything here that would actually be visible to the Customer. Things like 1x1 pixel images that load up silently and/or JavaScript tracking routines will be fine. Google® Analytics code works just fine, AdSense® performance tracking, as well as Yahoo® tracking and other affiliate network codes are all OK here.<br /><br />' . "\n";
57
  echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
58
  echo '<ul>' . "\n";
59
+ echo '<li><code>%%subscr_id%% = The PayPal® Subscription ID, which remains constant throughout any &amp; all future payments.</code> [ <a href="#" onclick="alert(\'There is one exception. If you are selling Lifetime or Fixed-Term ( non-recurring ) access, using a Buy It Now button; the %%subscr_id%% is actually set to the Transaction ID for the purchase.\\n\\nPayPal® does not provide a specific Subscription ID for Buy It Now purchases. Since Lifetime &amp; Fixed-Term Subscriptions are NOT recurring ( i.e. there is only ONE payment ), using the Transaction ID as the Subscription ID is a graceful way to deal with this minor conflict.\'); return false;">?</a> ]</li>' . "\n";
60
+ echo '<li><code>%%initial%% = The Initial Fee charged during signup. If you offered a free trial, this will be 0.</code> [ <a href="#" onclick="alert(\'This will always represent the amount of money the Customer spent, whenever they initially signed up, no matter what. If a Customer signs up, under the terms of a free trial period, this will be 0.\'); return false;">?</a> ]</li>' . "\n";
61
+ echo '<li><code>%%regular%% = The Regular Amount of the Subscription. This value is always > 0, no matter what.</code> [ <a href="#" onclick="alert(\'This is how much the Subscription costs after an initial period expires. The %%regular%% rate is always > 0. If you did not offer an initial period, %%initial%% and %%regular%% will be equal to the same thing.\'); return false;">?</a> ]</li>' . "\n";
62
+ echo '<li><code>%%recurring%% = This is the amount that will be charged on a Recurring basis, or 0 if non-Recurring.</code> [ <a href="#" onclick="alert(\'If recurring payments have not been required, this will be equal to 0. That being said, %%regular%% &amp; %%recurring%% are usually the same value. This variable can be used in two different ways. You can use it to determine what the regular recurring rate is, or to determine whether the Subscription will recur or not. If it is going to recur, %%recurring%% will be > 0.\\n\\nThe only time this is NOT equal to the %%regular%% rate, is when recurring payments are not required; and only a one-time regular rate applies.\'); return false;">?</a> ]</li>' . "\n";
63
+ echo '<li><code>%%first_name%% = The First Name of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
64
+ echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
65
+ echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased the Membership Subscription.</code></li>' . "\n";
66
+ echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased the Membership Subscription through PayPal®.</code></li>' . "\n";
67
+ echo '<li><code>%%item_number%% = The Item Number ( colon separated <em>level:custom_capabilities:fixed term</em> ) that the Subscription is for.</code></li>' . "\n";
68
+ echo '<li><code>%%item_name%% = The Item Name ( in other words, the associated membership Level Label that briefly describes the Item Number ).</code></li>' . "\n";
69
+ echo '<li><code>%%initial_term%% = This is the term length of the initial period. This will be a numeric value, followed by a space, then a single letter.</code> [ <a href="#" onclick="alert(\'Here are some examples:\\n\\n%%initial_term%% = 1 D ( this means 1 Day )\\n%%initial_term%% = 1 W ( this means 1 Week )\\n%%initial_term%% = 1 M ( this means 1 Month )\\n%%initial_term%% = 1 Y ( this means 1 Year )\\n\\nThe initial period never recurs, so this only lasts for the term length specified, then it is over. If no initial period was even offered, the value of %%initial_term%% will just be: 0 D, meaning zero days.\'); return false;">?</a> ]</li>' . "\n";
70
+ echo '<li><code>%%regular_term%% = This is the term length of the regular period. This will be a numeric value, followed by a space, then a single letter.</code> [ <a href="#" onclick="alert(\'Here are some examples:\\n\\n%%regular_term%% = 1 D ( this means 1 Day )\\n%%regular_term%% = 1 W ( this means 1 Week )\\n%%regular_term%% = 1 M ( this means 1 Month )\\n%%regular_term%% = 1 Y ( this means 1 Year )\\n%%regular_term%% = 1 L ( this means 1 Lifetime )\\n\\nThe regular term is usually recurring. So the regular term value represents the period ( or duration ) of each recurring period. If %%recurring%% = 0, then the regular term only applies once, because it is not recurring. So if it is not recurring, the value of %%regular_term%% simply represents how long their membership privileges are going to last after the %%initial_term%% has expired, if there was an initial term. The value of this variable ( %%regular_term%% ) will never be empty, it will always be at least: 1 D, meaning 1 day. No exceptions.\'); return false;">?</a> ]</li>' . "\n";
71
  echo '</ul>' . "\n";
72
  echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
73
  echo '<ul>' . "\n";
74
  echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
75
  echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</code></li>' . "\n";
76
  echo '</ul>' . "\n";
77
+ echo '<strong>This example uses cv1 to track a User\'s IP address:</strong><br />' . "\n";
78
+ echo '<em>( The IP address could be referenced in your Tracking Code using %%cv1%% )</em><br />' . "\n";
79
+ echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
80
+ echo '</td>' . "\n";
81
+ /**/
82
+ echo '</tr>' . "\n";
83
+ echo '</tbody>' . "\n";
84
+ echo '</table>' . "\n";
85
+ echo '</div>' . "\n";
86
+ /**/
87
+ echo '</div>' . "\n";
88
+ /**/
89
+ echo '<div class="ws-menu-page-group" title="Specific Post/Page Tracking Codes">' . "\n";
90
+ /**/
91
+ echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-tracking-section">' . "\n";
92
+ echo '<h3>Tracking Codes For Specific Post/Page Access ( optional )</h3>' . "\n";
93
+ echo '<p>If you use affiliate software, a list server, tracking codes from advertising networks, or the like; you\'ll want to read this section. The HTML' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["is_wpmu_farm"]) ? ' and/or PHP' : '') . ' code that you enter below, will be loaded up in a web browser, after a Customer returns from a successful transaction at PayPal®; specifically for Post/Page Access. These Codes are NOT injected for any type of Member Level Access. These are only for Specific Post/Page transactions. The Tracking Codes that you enter below, will be displayed in the footer section of your WordPress® theme, after a Customer returns from PayPal®.</p>' . "\n";
94
+ echo '<table class="form-table">' . "\n";
95
+ echo '<tbody>' . "\n";
96
+ echo '<tr>' . "\n";
97
+ /**/
98
+ echo '<th>' . "\n";
99
+ echo '<label for="ws-plugin--s2member-sp-tracking-codes">' . "\n";
100
+ echo 'Specific Post/Page Tracking Codes:' . "\n";
101
+ echo '</label>' . "\n";
102
+ echo '</th>' . "\n";
103
+ /**/
104
+ echo '</tr>' . "\n";
105
+ echo '<tr>' . "\n";
106
+ /**/
107
+ echo '<td>' . "\n";
108
+ echo '<textarea name="ws_plugin__s2member_sp_tracking_codes" id="ws-plugin--s2member-sp-tracking-codes" rows="8" wrap="off" spellcheck="false" style="font-family:Consolas, monospace;">' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_tracking_codes"]) . '</textarea><br />' . "\n";
109
+ echo 'Any valid XHTML / JavaScript' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["is_wpmu_farm"]) ? ' ( or even PHP )' : '') . ' code will work just fine here. Just try not to put anything here that would actually be visible to the Customer. Things like 1x1 pixel images that load up silently and/or JavaScript tracking routines will be fine. Google® Analytics code works just fine, AdSense® performance tracking, as well as Yahoo® tracking and other affiliate network codes are all OK here.<br /><br />' . "\n";
110
+ echo '<strong>You can also use these special replacement codes if you need them:</strong>' . "\n";
111
+ echo '<ul>' . "\n";
112
+ echo '<li><code>%%txn_id%% = The PayPal® Transaction ID. PayPal® assigns a unique identifier for every purchase.</code></li>' . "\n";
113
+ echo '<li><code>%%amount%% = The full Amount that you charged for Specific Post/Page Access. This value will always be > 0.</code></li>' . "\n";
114
+ echo '<li><code>%%first_name%% = The First Name of the Customer who purchased Specific Post/Page Access through PayPal®.</code></li>' . "\n";
115
+ echo '<li><code>%%last_name%% = The Last Name of the Customer who purchased Specific Post/Page Access through PayPal®.</code></li>' . "\n";
116
+ echo '<li><code>%%full_name%% = The Full Name ( First & Last ) of the Customer who purchased Specific Post/Page Access.</code></li>' . "\n";
117
+ echo '<li><code>%%payer_email%% = The Email Address of the Customer who purchased Specific Post/Page Access through PayPal®.</code></li>' . "\n";
118
+ echo '<li><code>%%item_number%% = The Item Number. Ex: <em>sp:13,24,36:72</em> ( translates to: <em>sp:comma-delimited IDs:expiration hours</em> ).</code></li>' . "\n";
119
+ echo '<li><code>%%item_name%% = The Item Name. In other words, a brief description, detailing what this purchase was for.</code></li>' . "\n";
120
+ echo '</ul>' . "\n";
121
+ echo '<strong>Custom replacement codes can also be inserted using these instructions:</strong>' . "\n";
122
+ echo '<ul>' . "\n";
123
+ echo '<li><code>%%cv0%% = The domain of your site, which is passed through to PayPal® using the `custom` field in your PayPal® Button Code.</code></li>' . "\n";
124
+ echo '<li><code>%%cv1%% = If you need to track additional custom variables, you can pipe delimit them into the `custom` field of your Button Code like this: &lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|cv1|cv2|cv3" /&gt;. You can have an unlimited number of custom variables that track IP addresses, affiliate IDs, etc. In some cases you may need to use PHP code to insert a value into the custom field dynamically. Obviously this is for advanced webmasters, but the functionality has been made available for those who need it.</code></li>' . "\n";
125
+ echo '</ul>' . "\n";
126
+ echo '<strong>This example uses cv1 to track a User\'s IP address:</strong><br />' . "\n";
127
+ echo '<em>( The IP address could be referenced in your Tracking Code using %%cv1%% )</em><br />' . "\n";
128
  echo '<code>&lt;input type="hidden" name="custom" value="' . $_SERVER["HTTP_HOST"] . '|&lt;?php echo $_SERVER["REMOTE_ADDR"]; ?&gt;" /&gt;</code>' . "\n";
129
  echo '</td>' . "\n";
130
  /**/
141
  echo '<h3>Integrating iDevAffiliate® ( affiliate program management )</h3>' . "\n";
142
  echo '<a href="http://www.idevdirect.com/14200.html" target="_blank"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/idev-logo.gif" class="ws-menu-page-right" style="width:125px; height:125px; border:0;" alt="." /></a>' . "\n";
143
  echo '<p>Adding affiliate tracking software to your site is one of the most effective ways to achieve more sales, more traffic, and more search engine ranking. <a href="http://www.idevdirect.com/14200.html" target="_blank" rel="external">iDevAffiliate®</a> ( an affiliate management portal ), installs in just minutes, and can be integrated seamlessly with s2Member. We recommend <a href="http://www.idevdirect.com/14200.html" target="_blank" rel="external">iDevAffiliate® Standard</a> ( $99 ) because of its proven track record, and its ability to integrate with s2Member using a variety of techniques. The most popular being a Hidden Image Tag.</p>' . "\n";
144
+ echo '<p>If you choose to <a href="http://www.idevdirect.com/14200.html" target="_blank" rel="external">install iDevAffiliate®</a>, you will need to configure your <code>iDevAffiliate® -> Shopping Cart Integration</code>. Please choose <code>Generic Tracking Pixel</code>. Then, grab your Hidden Image Tag, and pop the code provided by iDevAffiliate® into the Custom Tracking field at the top of this page. You MUST also add replacement codes to your Hidden Image Tag. To save you some trouble, we\'ve provided two examples below. The first example is for Signup Tracking ( Membership Access ), and the second example is for Specific Post/Page Tracking. The variables are different, depending on which type of transaction you\'re tracking.</p>' . "\n";
145
+ echo '<div class="ws-menu-page-hr"></div>' . "\n";
146
  echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/idev-signup-tracking-code.php"), true) . '</p>' . "\n";
147
+ echo '<div class="ws-menu-page-hr"></div>' . "\n";
148
+ echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/idev-sp-tracking-code.php"), true) . '</p>' . "\n";
149
+ echo '<div class="ws-menu-page-hr"></div>' . "\n";
150
  echo '<p>Your <code>profile</code> ID will be assigned by iDevAffiliate®. Be sure to replace <code>profile=123</code> with your own profile ID.</p>' . "\n";
151
  echo '<p><em><strong>*Tip*</strong> iDevAffiliate® also provides an alternative method, using a 3rd-party call. The alternative 3rd-party call, could be used with <code>s2Member -> API Notifications.</code> A 3rd-party call, is essentially an HTTP connection that runs silently behind-the-scene, as opposed to being loaded in a browser. It\'s a bit more powerful, but also more advanced.</em></p>' . "\n";
152
  echo '</div>' . "\n";
159
  echo '<h3>Integrating ShareASale® ( affiliate program management )</h3>' . "\n";
160
  echo '<a href="http://www.shareasale.com/merchantsignup.cfm" target="_blank"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/sas-logo.png" class="ws-menu-page-right" style="width:125px; height:125px; border:0;" alt="." /></a>' . "\n";
161
  echo '<p>Established in 2000, <a href="http://www.shareasale.com/merchantsignup.cfm" target="_blank" rel="external">ShareASale®</a> provides award winning technology and service; which will enable you to connect with a network of established affiliates, as well as recruit new ones. Joining ShareASale®, maximizes your ability to reach the greatest number of affiliates, with the least amount of work. At ShareASale®, you\'ll have access to an existing affiliate-base. You place your site on the market, and let their existing affiliates promote your products/services.</p>' . "\n";
162
+ echo '<p>If you <a href="http://www.shareasale.com/merchantsignup.cfm" target="_blank" rel="external">become a Merchant at ShareASale®</a>, you will need to configure your <code>ShareASale® -> Sale Tracking</code>. Grab your Hidden Image Tag, and pop the code provided by ShareASale® into the Custom Tracking field at the top of this page. You MUST also add replacement codes to your Hidden Image Tag. To save you some trouble, we\'ve provided two examples below. The first example is for Signup Tracking ( Membership Access ), and the second example is for Specific Post/Page Tracking. The variables are different, depending on which type of transaction you\'re tracking.</p>' . "\n";
163
+ echo '<div class="ws-menu-page-hr"></div>' . "\n";
164
  echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/sas-signup-tracking-code.php"), true) . '</p>' . "\n";
165
+ echo '<div class="ws-menu-page-hr"></div>' . "\n";
166
+ echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/sas-sp-tracking-code.php"), true) . '</p>' . "\n";
167
+ echo '<div class="ws-menu-page-hr"></div>' . "\n";
168
  echo '<p>Your <code>merchantID</code> will be assigned by ShareASale®. Be sure to replace <code>merchantID=123</code> with the one they assign you.</p>' . "\n";
169
  echo '<p><em><strong>*Tip*</strong> ShareASale® also provides an alternative method, using a 3rd-party call. The alternative 3rd-party call, could be used with <code>s2Member -> API Notifications.</code> A 3rd-party call, is essentially an HTTP connection that runs silently behind-the-scene, as opposed to being loaded in a browser. It\'s a bit more powerful, but also more advanced.</em></p>' . "\n";
170
  echo '</div>' . "\n";
171
  /**/
172
  echo '</div>' . "\n";
173
  /**/
 
 
 
 
 
 
 
 
 
174
  echo '<div class="ws-menu-page-group" title="Other Tracking Methods Available">' . "\n";
175
  /**/
176
  echo '<div class="ws-menu-page-section ws-plugin--s2member-other-methods-section">' . "\n";
177
  echo '<h3>Other Tracking Methods Are Available ( there\'s always a way )</h3>' . "\n";
178
+ echo '<p>Check the s2Member API Notifications panel. You\'ll find additional layers of automation available through the use of the `Signup`, `Registration`, `Payment`, `EOT/Deletion`, `Refund/Reversal`, and `Specific Post/Page` notifications that are available to you through the s2Member API. The s2Member API Notifications make it possible to integrate with 3rd party applications; like list servers, affiliate programs, and other back-office routines; in more advanced ways. Since the s2Member API Notifications operate silently on the back-end, in conjunction with the PayPal® IPN system, they tend to be more reliable and also more versatile. That being said, nothing replaces the simplicity of Tracking Codes. The more advanced API Notifications are NOT always the best tool for the job. For instance, API Notifications will NOT work with Google® Analytics, or 1 pixel &lt;img&gt; tags. They operate silently behind-the-scene, using cURL connections, as opposed to being loaded in a browser.</p>' . "\n";
179
  echo '</div>' . "\n";
180
  /**/
181
  echo '</div>' . "\n";
includes/syscon.inc.php CHANGED
@@ -18,6 +18,10 @@ Direct access denial.
18
  if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
19
  exit;
20
  /*
 
 
 
 
21
  Detect if we are inside an MU installation.
22
  */
23
  if (($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["is_wpmu"] = function_exists ("wpmu_current_site"))/**/
@@ -68,19 +72,22 @@ function ws_plugin__s2member_configure_options_and_their_defaults ($options = FA
68
  "sec_encryption_key" => "", /* For security. This keeps each installation unique. */
69
  "sec_encryption_key_history" => array (), /* This keeps a history of the last 10 keys. */
70
  /**/
 
 
 
71
  "run_deactivation_routines" => "1", /* Should deactivation routines be processed? */
72
  /**/
73
- "custom_reg_fields" => "", /* A comma delimited list of custom fields to collect/use. */
74
- "custom_reg_password" => "0", /* Allow users to register their own custom password? */
75
- "custom_reg_opt_in" => "1", /* Use a double opt-in checkbox on the registration form? */
76
  "custom_reg_opt_in_label" => "Yes, I want to receive updates via email.", /* Label. */
77
  /**/
78
- "allow_subscribers_in" => "0", /* Allow subscribers to access the login_welcome_page? */
79
- "force_admin_lockouts" => "0", /* Redirects admin pages/profile to the login_welcome_page. */
80
  /**/
81
- "login_welcome_page" => "", /* Defaults to the home page. */
82
- "login_redirection_override" => "", /* Alternate redirection location; instead of the welcome page. */
83
- "membership_options_page" => "", /* Defaults to the home page. */
84
  /**/
85
  "login_reg_background_color" => "FFFFFF", /* Defaults to white, and the bg.png is also white. */
86
  "login_reg_background_image" => $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . "/images/bg.png",/**/
@@ -102,38 +109,38 @@ function ws_plugin__s2member_configure_options_and_their_defaults ($options = FA
102
  "paypal_business" => "", /* Paypal business email address for their account. */
103
  "paypal_identity_token" => "", /* Paypal payment data transfer identity token. */
104
  /**/
105
- "signup_tracking_codes" => "", /* s2Member tracking codes injected on signup. */
106
- /**/
107
  "signup_email_subject" => "Congratulations! ( your membership has been approved )",/**/
108
  "signup_email_message" => "Thanks %%first_name%%! Your membership has been approved.\n\nIf you haven't already done so, the next step is to Register a Username.\n\nComplete your registration here:\n%%registration_url%%\n\nIf you have any trouble, please feel free to contact us.\n\nBest Regards,\n" . get_bloginfo ("name"),/**/
109
  /**/
110
- "single_page_email_subject" => "Thank You! ( instructions for access )",/**/
111
- "single_page_email_message" => "Thanks %%first_name%%!\n\n%%item_name%%\n\nYour order can be retrieved here:\n%%sp_access_url%%\n( link expires in %%sp_access_exp%% )\n\nIf you have any trouble, please feel free to contact us.\n\nBest Regards,\n" . get_bloginfo ("name"),/**/
 
112
  /**/
113
  "mailchimp_api_key" => "", /* MailChimp® API Key for MailChimp® integration. */
114
- "level0_mailchimp_list_ids" => "", /* Comma delimited list of MailChimp® List IDs. */
115
- "level1_mailchimp_list_ids" => "", /* Comma delimited list of MailChimp® List IDs. */
116
- "level2_mailchimp_list_ids" => "", /* Comma delimited list of MailChimp® List IDs. */
117
- "level3_mailchimp_list_ids" => "", /* Comma delimited list of MailChimp® List IDs. */
118
- "level4_mailchimp_list_ids" => "", /* Comma delimited list of MailChimp® List IDs. */
119
  /**/
120
- "level0_aweber_list_ids" => "", /* Comma delimited list of AWeber® List IDs. */
121
- "level1_aweber_list_ids" => "", /* Comma delimited list of AWeber® List IDs. */
122
- "level2_aweber_list_ids" => "", /* Comma delimited list of AWeber® List IDs. */
123
- "level3_aweber_list_ids" => "", /* Comma delimited list of AWeber® List IDs. */
124
- "level4_aweber_list_ids" => "", /* Comma delimited list of AWeber® List IDs. */
125
  /**/
126
- "signup_notification_urls" => "", /* s2Member signup notification urls. */
127
- "registration_notification_urls" => "", /* s2Member reg notification urls. */
128
- "payment_notification_urls" => "", /* s2Member payment notification urls. */
129
- "eot_del_notification_urls" => "", /* s2Member eot/del notification urls. */
130
- "ref_rev_notification_urls" => "", /* s2Member ref/rev notification urls. */
131
- "sp_notification_urls" => "", /* s2Member single-page notification urls. */
132
  /**/
133
- "level1_label" => "Bronze", /* This is just an initial generic level label. */
134
- "level2_label" => "Silver", /* This is just an initial generic level label. */
135
- "level3_label" => "Gold", /* This is just an initial generic level label. */
136
- "level4_label" => "Platinum", /* This is just an initial generic level label. */
137
  /**/
138
  "level1_file_downloads_allowed" => "", /* This should always be numeric or empty. */
139
  "level2_file_downloads_allowed" => "", /* This should always be numeric or empty. */
@@ -145,37 +152,38 @@ function ws_plugin__s2member_configure_options_and_their_defaults ($options = FA
145
  "level3_file_downloads_allowed_days" => "", /* This should be numeric or empty. */
146
  "level4_file_downloads_allowed_days" => "", /* This should be numeric or empty. */
147
  /**/
148
- "file_download_limit_exceeded_page" => "", /* Defaults to the home page. */
149
- "file_download_inline_extensions" => "", /* List of extensions to serve inline. */
150
  /**/
151
- "level1_ruris" => "", /* It is ok for these to just be empty strings. */
152
- "level2_ruris" => "", /* It is ok for these to just be empty strings. */
153
- "level3_ruris" => "", /* It is ok for these to just be empty strings. */
154
- "level4_ruris" => "", /* It is ok for these to just be empty strings. */
155
  /**/
156
- "level1_catgs" => "", /* It is ok for these to just be empty strings. */
157
- "level2_catgs" => "", /* It is ok for these to just be empty strings. */
158
- "level3_catgs" => "", /* It is ok for these to just be empty strings. */
159
- "level4_catgs" => "", /* It is ok for these to just be empty strings. */
160
  /**/
161
- "level1_ptags" => "", /* It is ok for these to just be empty strings. */
162
- "level2_ptags" => "", /* It is ok for these to just be empty strings. */
163
- "level3_ptags" => "", /* It is ok for these to just be empty strings. */
164
- "level4_ptags" => "", /* It is ok for these to just be empty strings. */
165
  /**/
166
- "level1_posts" => "", /* It is ok for these to just be empty strings. */
167
- "level2_posts" => "", /* It is ok for these to just be empty strings. */
168
- "level3_posts" => "", /* It is ok for these to just be empty strings. */
169
- "level4_posts" => "", /* It is ok for these to just be empty strings. */
170
  /**/
171
- "level1_pages" => "", /* It is ok for these to just be empty strings. */
172
- "level2_pages" => "", /* It is ok for these to just be empty strings. */
173
- "level3_pages" => "", /* It is ok for these to just be empty strings. */
174
- "level4_pages" => "", /* It is ok for these to just be empty strings. */
175
  /**/
176
- "single_pages" => "", /* It is ok for these to just be empty strings. */
177
  /**/
178
- "membership_eot_behavior" => "demote"); /* Demote or delete Members? */
 
179
  /*
180
  Here they are merged. user options will overwrite some or all default values.
181
  */
@@ -191,6 +199,21 @@ function ws_plugin__s2member_configure_options_and_their_defaults ($options = FA
191
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_logo_src"] === $default_options["login_reg_logo_src"])
192
  $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_logo_src_width"] = $default_options["login_reg_logo_src_width"];
193
  /*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  Validate each option, possibly reverting back to the default value if invalid.
195
  Also check if options were passed in on some of these, in case empty values are to be allowed.
196
  */
@@ -214,6 +237,12 @@ function ws_plugin__s2member_configure_options_and_their_defaults ($options = FA
214
  else if ($key === "sec_encryption_key_history" && (!is_array ($value) || empty ($value)))
215
  $value = $default_options[$key];
216
  /**/
 
 
 
 
 
 
217
  else if ($key === "run_deactivation_routines" && (!is_string ($value) || !is_numeric ($value)))
218
  $value = $default_options[$key];
219
  /**/
@@ -292,10 +321,13 @@ function ws_plugin__s2member_configure_options_and_their_defaults ($options = FA
292
  else if ($key === "signup_email_message" && (!is_string ($value) || !strlen ($value)))
293
  $value = $default_options[$key];
294
  /**/
295
- else if ($key === "single_page_email_subject" && (!is_string ($value) || !strlen ($value)))
296
  $value = $default_options[$key];
297
  /**/
298
- else if ($key === "single_page_email_message" && (!is_string ($value) || !strlen ($value)))
 
 
 
299
  $value = $default_options[$key];
300
  /**/
301
  else if ($key === "mailchimp_api_key" && (!is_string ($value) || !strlen ($value)))
@@ -364,11 +396,14 @@ function ws_plugin__s2member_configure_options_and_their_defaults ($options = FA
364
  else if (preg_match ("/^level[1-4]_pages$/", $key) && (!is_string ($value) || !($value = (($value === "all") ? $value : preg_replace ("/[^0-9,]/", "", $value)))))
365
  $value = $default_options[$key];
366
  /**/
367
- else if ($key === "single_pages" && (!is_string ($value) || !($value = preg_replace ("/[^0-9,]/", "", $value))))
368
  $value = $default_options[$key];
369
  /**/
370
  else if ($key === "membership_eot_behavior" && (!is_string ($value) || !preg_match ("/^(demote|delete)$/", $value)))
371
  $value = $default_options[$key];
 
 
 
372
  }
373
  /*
374
  Keeps a history of the last 10 Security Encryption Keys configured for this installation.
18
  if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
19
  exit;
20
  /*
21
+ Configure the version for this release.
22
+ */
23
+ $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["version"] = "3.0"; /* Since s2Member 3.0. */
24
+ /*
25
  Detect if we are inside an MU installation.
26
  */
27
  if (($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["is_wpmu"] = function_exists ("wpmu_current_site"))/**/
72
  "sec_encryption_key" => "", /* For security. This keeps each installation unique. */
73
  "sec_encryption_key_history" => array (), /* This keeps a history of the last 10 keys. */
74
  /**/
75
+ "max_ip_restriction" => "5", /* Maximum IPs on record for each Username/Post/Page. */
76
+ "max_ip_restriction_time" => "3600", /* How long before restrictions are lifted? */
77
+ /**/
78
  "run_deactivation_routines" => "1", /* Should deactivation routines be processed? */
79
  /**/
80
+ "custom_reg_fields" => "", /* A comma-delimited list of Custom Fields to collect/use. */
81
+ "custom_reg_password" => "0", /* Allow users to register their own Custom Password? */
82
+ "custom_reg_opt_in" => "1", /* Use a Double Opt-In Checkbox on the Registration Form? */
83
  "custom_reg_opt_in_label" => "Yes, I want to receive updates via email.", /* Label. */
84
  /**/
85
+ "allow_subscribers_in" => "0", /* Allow Subscribers to access the Login Welcome Page? */
86
+ "force_admin_lockouts" => "0", /* Redirects admin Pages/Profile to the Login Welcome Page. */
87
  /**/
88
+ "login_welcome_page" => "", /* Defaults to the Home Page. */
89
+ "login_redirection_override" => "", /* Alternate redirection location; instead of the Welcome Page. */
90
+ "membership_options_page" => "", /* Defaults to the Home Page. */
91
  /**/
92
  "login_reg_background_color" => "FFFFFF", /* Defaults to white, and the bg.png is also white. */
93
  "login_reg_background_image" => $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . "/images/bg.png",/**/
109
  "paypal_business" => "", /* Paypal business email address for their account. */
110
  "paypal_identity_token" => "", /* Paypal payment data transfer identity token. */
111
  /**/
112
+ "signup_tracking_codes" => "", /* Signup Tracking Codes. */
 
113
  "signup_email_subject" => "Congratulations! ( your membership has been approved )",/**/
114
  "signup_email_message" => "Thanks %%first_name%%! Your membership has been approved.\n\nIf you haven't already done so, the next step is to Register a Username.\n\nComplete your registration here:\n%%registration_url%%\n\nIf you have any trouble, please feel free to contact us.\n\nBest Regards,\n" . get_bloginfo ("name"),/**/
115
  /**/
116
+ "sp_tracking_codes" => "", /* Specific Post/Page Tracking. */
117
+ "sp_email_subject" => "Thank You! ( instructions for access )",/**/
118
+ "sp_email_message" => "Thanks %%first_name%%!\n\n%%item_name%%\n\nYour order can be retrieved here:\n%%sp_access_url%%\n( link expires in %%sp_access_exp%% )\n\nIf you have any trouble, please feel free to contact us.\n\nBest Regards,\n" . get_bloginfo ("name"),/**/
119
  /**/
120
  "mailchimp_api_key" => "", /* MailChimp® API Key for MailChimp® integration. */
121
+ "level0_mailchimp_list_ids" => "", /* A comma-delimited list of MailChimp® List IDs. */
122
+ "level1_mailchimp_list_ids" => "", /* A comma-delimited list of MailChimp® List IDs. */
123
+ "level2_mailchimp_list_ids" => "", /* A comma-delimited list of MailChimp® List IDs. */
124
+ "level3_mailchimp_list_ids" => "", /* A comma-delimited list of MailChimp® List IDs. */
125
+ "level4_mailchimp_list_ids" => "", /* A comma-delimited list of MailChimp® List IDs. */
126
  /**/
127
+ "level0_aweber_list_ids" => "", /* A comma-delimited list of AWeber® List IDs. */
128
+ "level1_aweber_list_ids" => "", /* A comma-delimited list of AWeber® List IDs. */
129
+ "level2_aweber_list_ids" => "", /* A comma-delimited list of AWeber® List IDs. */
130
+ "level3_aweber_list_ids" => "", /* A comma-delimited list of AWeber® List IDs. */
131
+ "level4_aweber_list_ids" => "", /* A comma-delimited list of AWeber® List IDs. */
132
  /**/
133
+ "signup_notification_urls" => "", /* s2Member Signup Notification urls. */
134
+ "registration_notification_urls" => "", /* s2Member Reg Notification urls. */
135
+ "payment_notification_urls" => "", /* s2Member Payment Notification urls. */
136
+ "eot_del_notification_urls" => "", /* s2Member Eot/del Notification urls. */
137
+ "ref_rev_notification_urls" => "", /* s2Member Ref/rev Notification urls. */
138
+ "sp_notification_urls" => "", /* s2Member Specific Post/Page Notification urls. */
139
  /**/
140
+ "level1_label" => "Bronze", /* This is just an initial generic Level Label. */
141
+ "level2_label" => "Silver", /* This is just an initial generic Level Label. */
142
+ "level3_label" => "Gold", /* This is just an initial generic Level Label. */
143
+ "level4_label" => "Platinum", /* This is just an initial generic Level Label. */
144
  /**/
145
  "level1_file_downloads_allowed" => "", /* This should always be numeric or empty. */
146
  "level2_file_downloads_allowed" => "", /* This should always be numeric or empty. */
152
  "level3_file_downloads_allowed_days" => "", /* This should be numeric or empty. */
153
  "level4_file_downloads_allowed_days" => "", /* This should be numeric or empty. */
154
  /**/
155
+ "file_download_limit_exceeded_page" => "", /* Defaults to the Home Page. */
156
+ "file_download_inline_extensions" => "", /* List of Extensions to serve Inline. */
157
  /**/
158
+ "level1_ruris" => "", /* A line-delimited list of URIs, and/or URI fragments. */
159
+ "level2_ruris" => "", /* A line-delimited list of URIs, and/or URI fragments. */
160
+ "level3_ruris" => "", /* A line-delimited list of URIs, and/or URI fragments. */
161
+ "level4_ruris" => "", /* A line-delimited list of URIs, and/or URI fragments. */
162
  /**/
163
+ "level1_catgs" => "", /* A comma-delimited list of Category IDs to protect. */
164
+ "level2_catgs" => "", /* A comma-delimited list of Category IDs to protect. */
165
+ "level3_catgs" => "", /* A comma-delimited list of Category IDs to protect. */
166
+ "level4_catgs" => "", /* A comma-delimited list of Category IDs to protect. */
167
  /**/
168
+ "level1_ptags" => "", /* A comma-delimited list of Page/Post Tags to protect. */
169
+ "level2_ptags" => "", /* A comma-delimited list of Page/Post Tags to protect. */
170
+ "level3_ptags" => "", /* A comma-delimited list of Page/Post Tags to protect. */
171
+ "level4_ptags" => "", /* A comma-delimited list of Page/Post Tags to protect. */
172
  /**/
173
+ "level1_posts" => "", /* A comma-delimited list of Post IDs to protect. */
174
+ "level2_posts" => "", /* A comma-delimited list of Post IDs to protect. */
175
+ "level3_posts" => "", /* A comma-delimited list of Post IDs to protect. */
176
+ "level4_posts" => "", /* A comma-delimited list of Post IDs to protect. */
177
  /**/
178
+ "level1_pages" => "", /* A comma-delimited list of Page IDs to protect. */
179
+ "level2_pages" => "", /* A comma-delimited list of Page IDs to protect. */
180
+ "level3_pages" => "", /* A comma-delimited list of Page IDs to protect. */
181
+ "level4_pages" => "", /* A comma-delimited list of Page IDs to protect. */
182
  /**/
183
+ "specific_ids" => "", /* Comma-delimited list of Specific Post/Page IDs. */
184
  /**/
185
+ "membership_eot_behavior" => "demote", /* Demote or delete Members? */
186
+ "auto_eot_system_enabled" => "1"); /* Enabled by default; when options are updated. */
187
  /*
188
  Here they are merged. user options will overwrite some or all default values.
189
  */
199
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_logo_src"] === $default_options["login_reg_logo_src"])
200
  $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_logo_src_width"] = $default_options["login_reg_logo_src_width"];
201
  /*
202
+ Backward compatibility for `single_page_email_subject`, which was renamed to `sp_email_subject` in v3.0.
203
+ */
204
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["single_page_email_subject"])
205
+ $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_email_subject"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["single_page_email_subject"];
206
+ /*
207
+ Backward compatibility for `single_page_email_message`, which was renamed to `sp_email_message` in v3.0.
208
+ */
209
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["single_page_email_message"]) /* Also corrects a typo in the original default for this option. Should be %%sp_access_url%%. */
210
+ $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_email_message"] = preg_replace ("/%%access_url%%/", "%%sp_access_url%%", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["single_page_email_message"]);
211
+ /*
212
+ Backward compatibility for `single_pages`, which was renamed to `specific_ids` in v3.0.
213
+ */
214
+ if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["single_pages"])
215
+ $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["specific_ids"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["single_pages"];
216
+ /*
217
  Validate each option, possibly reverting back to the default value if invalid.
218
  Also check if options were passed in on some of these, in case empty values are to be allowed.
219
  */
237
  else if ($key === "sec_encryption_key_history" && (!is_array ($value) || empty ($value)))
238
  $value = $default_options[$key];
239
  /**/
240
+ else if ($key === "max_ip_restriction" && (!is_string ($value) || !is_numeric ($value) || $value < 2 || $value > 100))
241
+ $value = $default_options[$key];
242
+ /**/
243
+ else if ($key === "max_ip_restriction_time" && (!is_string ($value) || !is_numeric ($value) || $value < 900 || $value > 604800))
244
+ $value = $default_options[$key];
245
+ /**/
246
  else if ($key === "run_deactivation_routines" && (!is_string ($value) || !is_numeric ($value)))
247
  $value = $default_options[$key];
248
  /**/
321
  else if ($key === "signup_email_message" && (!is_string ($value) || !strlen ($value)))
322
  $value = $default_options[$key];
323
  /**/
324
+ else if ($key === "sp_tracking_codes" && (!is_string ($value) || !strlen ($value)))
325
  $value = $default_options[$key];
326
  /**/
327
+ else if ($key === "sp_email_subject" && (!is_string ($value) || !strlen ($value)))
328
+ $value = $default_options[$key];
329
+ /**/
330
+ else if ($key === "sp_email_message" && (!is_string ($value) || !strlen ($value)))
331
  $value = $default_options[$key];
332
  /**/
333
  else if ($key === "mailchimp_api_key" && (!is_string ($value) || !strlen ($value)))
396
  else if (preg_match ("/^level[1-4]_pages$/", $key) && (!is_string ($value) || !($value = (($value === "all") ? $value : preg_replace ("/[^0-9,]/", "", $value)))))
397
  $value = $default_options[$key];
398
  /**/
399
+ else if ($key === "specific_ids" && (!is_string ($value) || !($value = preg_replace ("/[^0-9,]/", "", $value))))
400
  $value = $default_options[$key];
401
  /**/
402
  else if ($key === "membership_eot_behavior" && (!is_string ($value) || !preg_match ("/^(demote|delete)$/", $value)))
403
  $value = $default_options[$key];
404
+ /**/
405
+ else if ($key === "auto_eot_system_enabled" && (!is_string ($value) || !is_numeric ($value)))
406
+ $value = $default_options[$key];
407
  }
408
  /*
409
  Keeps a history of the last 10 Security Encryption Keys configured for this installation.
includes/templates/buttons/sp-button.html CHANGED
@@ -12,7 +12,7 @@
12
  <input type="hidden" name="custom" value="%%domain%%" />
13
  <input type="hidden" name="currency_code" value="USD" />
14
  <input type="hidden" name="page_style" value="paypal" />
15
- <input type="hidden" name="item_name" value="Single-Page Access" />
16
  <input type="hidden" name="item_number" value="sp:0:72" />
17
  <input type="hidden" name="amount" value="0.01" />
18
  <!-- Displays The PayPal® Image Button -->
12
  <input type="hidden" name="custom" value="%%domain%%" />
13
  <input type="hidden" name="currency_code" value="USD" />
14
  <input type="hidden" name="page_style" value="paypal" />
15
+ <input type="hidden" name="item_name" value="Specific Post/Page Access" />
16
  <input type="hidden" name="item_number" value="sp:0:72" />
17
  <input type="hidden" name="amount" value="0.01" />
18
  <!-- Displays The PayPal® Image Button -->
includes/templates/options/currencies.html ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <optgroup label="Currency">
2
+ <option value="USD" title="U.S. Dollar">USD</option>
3
+ <option value="AUD" title="Australian Dollar">AUD</option>
4
+ <option value="BRL" title="Brazilian Real">BRL</option>
5
+ <option value="CAD" title="Canadian Dollar">CAD</option>
6
+ <option value="CZK" title="Czech Koruna">CZK</option>
7
+ <option value="DKK" title="Danish Krone">DKK</option>
8
+ <option value="EUR" title="Euro">EUR</option>
9
+ <option value="HKD" title="Hong Kong Dollar">HKD</option>
10
+ <option value="HUF" title="Hungarian Forint">HUF</option>
11
+ <option value="ILS" title="Israeli New Sheqel">ILS</option>
12
+ <option value="JPY" title="Japanese Yen">JPY</option>
13
+ <option value="MYR" title="Malaysian Ringgit">MYR</option>
14
+ <option value="MXN" title="Mexican Peso">MXN</option>
15
+ <option value="NOK" title="Norwegian Krone">NOK</option>
16
+ <option value="NZD" title="New Zealand Dollar">NZD</option>
17
+ <option value="PHP" title="Philippine Peso">PHP</option>
18
+ <option value="PLN" title="Polish Zloty">PLN</option>
19
+ <option value="GBP" title="Pound Sterling">GBP</option>
20
+ <option value="SGD" title="Singapore Dollar">SGD</option>
21
+ <option value="SEK" title="Swedish Krona">SEK</option>
22
+ <option value="CHF" title="Swiss Franc">CHF</option>
23
+ <option value="TWD" title="Taiwan New Dollar">TWD</option>
24
+ <option value="THB" title="Thai Baht">THB</option>
25
+ <option value="USD" title="U.S. Dollar">USD</option>
26
+ </optgroup>
includes/templates/options/index.php ADDED
File without changes
includes/templates/options/membership-modification-levels.html ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <optgroup label="Level #1">
2
+ <option value="upgrade:1">&uarr; Upgrade To Level #1</option>
3
+ <option value="downgrade:1">&darr; Downgrade To Level #1</option>
4
+ </optgroup>
5
+
6
+ <optgroup label="Level #2">
7
+ <option value="upgrade:2" selected="selected">&uarr; Upgrade To Level #2</option>
8
+ <option value="downgrade:2">&darr; Downgrade To Level #2</option>
9
+ </optgroup>
10
+
11
+ <optgroup label="Level #3">
12
+ <option value="upgrade:3">&uarr; Upgrade To Level #3</option>
13
+ <option value="downgrade:3">&darr; Downgrade To Level #3</option>
14
+ </optgroup>
15
+
16
+ <optgroup label="Level #4">
17
+ <option value="upgrade:4">&uarr; Upgrade To Level #4</option>
18
+ </optgroup>
includes/templates/options/membership-regular-terms.html ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <optgroup label="Recurring Subscriptions">
2
+ <option value="1-D-1">Daily ( recurring charge, for ongoing access )</option>
3
+ <option value="1-W-1">Weekly ( recurring charge, for ongoing access )</option>
4
+ <option value="1-M-1" selected="selected">Monthly ( recurring charge, for ongoing access )</option>
5
+ <option value="3-M-1">Quarterly ( recurring charge, for ongoing access )</option>
6
+ <option value="1-Y-1">Yearly ( recurring charge, for ongoing access )</option>
7
+ </optgroup>
8
+
9
+ <option disabled="disabled"></option>
10
+
11
+ <optgroup label="Non-Recurring Subscriptions">
12
+ <option value="1-D-0">One Time ( for 1 day access, non-recurring )</option>
13
+ <option value="2-D-0">One Time ( for 2 day access, non-recurring )</option>
14
+ <option value="3-D-0">One Time ( for 3 day access, non-recurring )</option>
15
+ <option value="4-D-0">One Time ( for 4 day access, non-recurring )</option>
16
+ <option value="5-D-0">One Time ( for 5 day access, non-recurring )</option>
17
+ <option value="6-D-0">One Time ( for 6 day access, non-recurring )</option>
18
+
19
+ <option value="1-W-0">One Time ( for 1 week access, non-recurring )</option>
20
+ <option value="2-W-0">One Time ( for 2 week access, non-recurring )</option>
21
+ <option value="3-W-0">One Time ( for 3 week access, non-recurring )</option>
22
+
23
+ <option value="1-M-0">One Time ( for 1 month access, non-recurring )</option>
24
+ <option value="2-M-0">One Time ( for 2 month access, non-recurring )</option>
25
+ <option value="3-M-0">One Time ( for 3 month access, non-recurring )</option>
26
+ <option value="4-M-0">One Time ( for 4 month access, non-recurring )</option>
27
+ <option value="5-M-0">One Time ( for 5 month access, non-recurring )</option>
28
+ <option value="6-M-0">One Time ( for 6 month access, non-recurring )</option>
29
+
30
+ <option value="1-Y-0">One Time ( for 1 year access, non-recurring )</option>
31
+ <option value="2-Y-0">One Time ( for 2 year access, non-recurring )</option>
32
+ <option value="3-Y-0">One Time ( for 3 year access, non-recurring )</option>
33
+ <option value="4-Y-0">One Time ( for 4 year access, non-recurring )</option>
34
+ <option value="5-Y-0">One Time ( for 5 year access, non-recurring )</option>
35
+ </optgroup>
36
+
37
+ <option disabled="disabled"></option>
38
+
39
+ <optgroup label="Non-Recurring / Buy Now!">
40
+ <option value="1-D-BN">One Time ( for 1 day access, non-recurring, no trial )</option>
41
+ <option value="2-D-BN">One Time ( for 2 day access, non-recurring, no trial )</option>
42
+ <option value="3-D-BN">One Time ( for 3 day access, non-recurring, no trial )</option>
43
+ <option value="4-D-BN">One Time ( for 4 day access, non-recurring, no trial )</option>
44
+ <option value="5-D-BN">One Time ( for 5 day access, non-recurring, no trial )</option>
45
+ <option value="6-D-BN">One Time ( for 6 day access, non-recurring, no trial )</option>
46
+
47
+ <option value="1-W-BN">One Time ( for 1 week access, non-recurring, no trial )</option>
48
+ <option value="2-W-BN">One Time ( for 2 week access, non-recurring, no trial )</option>
49
+ <option value="3-W-BN">One Time ( for 3 week access, non-recurring, no trial )</option>
50
+
51
+ <option value="1-M-BN">One Time ( for 1 month access, non-recurring, no trial )</option>
52
+ <option value="2-M-BN">One Time ( for 2 month access, non-recurring, no trial )</option>
53
+ <option value="3-M-BN">One Time ( for 3 month access, non-recurring, no trial )</option>
54
+ <option value="4-M-BN">One Time ( for 4 month access, non-recurring, no trial )</option>
55
+ <option value="5-M-BN">One Time ( for 5 month access, non-recurring, no trial )</option>
56
+ <option value="6-M-BN">One Time ( for 6 month access, non-recurring, no trial )</option>
57
+
58
+ <option value="1-Y-BN">One Time ( for 1 year access, non-recurring, no trial )</option>
59
+ <option value="2-Y-BN">One Time ( for 2 year access, non-recurring, no trial )</option>
60
+ <option value="3-Y-BN">One Time ( for 3 year access, non-recurring, no trial )</option>
61
+ <option value="4-Y-BN">One Time ( for 4 year access, non-recurring, no trial )</option>
62
+ <option value="5-Y-BN">One Time ( for 5 year access, non-recurring, no trial )</option>
63
+ <option value="1-L-BN">One Time ( for lifetime access, non-recurring, no trial )</option>
64
+ </optgroup>
includes/templates/options/membership-trial-terms.html ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <option value="D" selected="selected">Days</option>
2
+ <option value="W">Weeks</option>
3
+ <option value="M">Months</option>
4
+ <option value="Y">Years</option>
includes/templates/options/sp-hours.html ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <optgroup label="Expires In Hours">
2
+ <option value="2">Buy Now ( Specific Post/Page, link valid for 2 hours )</option>
3
+ <option value="4">Buy Now ( Specific Post/Page, link valid for 4 hours )</option>
4
+ <option value="6">Buy Now ( Specific Post/Page, link valid for 6 hours )</option>
5
+ <option value="8">Buy Now ( Specific Post/Page, link valid for 8 hours )</option>
6
+ <option value="10">Buy Now ( Specific Post/Page, link valid for 10 hours )</option>
7
+ <option value="12">Buy Now ( Specific Post/Page, link valid for 12 hours )</option>
8
+ </optgroup>
9
+
10
+ <optgroup label="Expires In Days">
11
+ <option value="24">Buy Now ( Specific Post/Page, link valid for 1 day )</option>
12
+ <option value="48">Buy Now ( Specific Post/Page, link valid for 2 days )</option>
13
+ <option value="72" selected="selected">Buy Now ( Specific Post/Page, link valid for 3 days )</option>
14
+ <option value="96">Buy Now ( Specific Post/Page, link valid for 4 days )</option>
15
+ <option value="120">Buy Now ( Specific Post/Page, link valid for 5 days )</option>
16
+ <option value="144">Buy Now ( Specific Post/Page, link valid for 6 days )</option>
17
+ </optgroup>
18
+
19
+ <optgroup label="Expires In Weeks">
20
+ <option value="168">Buy Now ( Specific Post/Page, link valid for 1 week )</option>
21
+ <option value="336">Buy Now ( Specific Post/Page, link valid for 2 weeks )</option>
22
+ <option value="504">Buy Now ( Specific Post/Page, link valid for 3 weeks )</option>
23
+ </optgroup>
24
+
25
+ <optgroup label="Expires In Months">
26
+ <option value="720">Buy Now ( Specific Post/Page, link valid for 1 month )</option>
27
+ <option value="1440">Buy Now ( Specific Post/Page, link valid for 2 months )</option>
28
+ <option value="2190">Buy Now ( Specific Post/Page, link valid for 3 months )</option>
29
+ <option value="4380">Buy Now ( Specific Post/Page, link valid for 6 months )</option>
30
+ </optgroup>
31
+
32
+ <optgroup label="Expires In Years">
33
+ <option value="8760">Buy Now ( Specific Post/Page, link valid for 1 year )</option>
34
+ <option value="17520">Buy Now ( Specific Post/Page, link valid for 2 years )</option>
35
+ <option value="26280">Buy Now ( Specific Post/Page, link valid for 3 years )</option>
36
+ <option value="35040">Buy Now ( Specific Post/Page, link valid for 4 years )</option>
37
+ <option value="43800">Buy Now ( Specific Post/Page, link valid for 5 years )</option>
38
+ </optgroup>
includes/templates/shortcodes/c-shortcode.html CHANGED
@@ -1 +1 @@
1
- [s2Member-PayPal-Button cb="1" /]
1
+ [s2Member-PayPal-Button cb="1" image="default" /]
includes/templates/shortcodes/shortcode.html CHANGED
@@ -1 +1 @@
1
- [s2Member-PayPal-Button level="%%level%%" ccaps="" desc="%%level_label%%" ps="paypal" cc="USD" custom="%%domain%%" tp="0" tt="D" ra="0.01" rp="1" rt="M" rr="1" /]
1
+ [s2Member-PayPal-Button level="%%level%%" ccaps="" desc="%%level_label%%" ps="paypal" cc="USD" custom="%%domain%%" tp="0" tt="D" ra="0.01" rp="1" rt="M" rr="1" image="default" /]
includes/templates/shortcodes/sp-shortcode.html CHANGED
@@ -1 +1 @@
1
- [s2Member-PayPal-Button page="0" exp="72" desc="Single-Page Access" ps="paypal" cc="USD" custom="%%domain%%" ra="0.01" sp="1" /]
1
+ [s2Member-PayPal-Button page="0" exp="72" desc="Specific Post/Page Access" ps="paypal" cc="USD" custom="%%domain%%" ra="0.01" sp="1" image="default" /]
readme.txt CHANGED
@@ -1,13 +1,12 @@
1
  === s2Member ( Membership w/ PayPal® Integration ) also works w/ BuddyPress ===
2
 
3
- Version: 2.9.4
4
- Stable tag: 2.9.4
5
  Framework: WS-P-2.1
6
 
7
  WordPress Compatible: yes
8
  BuddyPress Compatible: yes
9
- WordPress MU Compatible: soon
10
- MU Blog Farm Compatible: soon
11
 
12
  Tested up to: 3.0
13
  Requires at least: 2.8.4
@@ -35,21 +34,17 @@ s2Member is a full-featured membership management system for WordPress®. It emp
35
  2. Activate the plugin through the `Plugins` menu in WordPress®.
36
  3. Navigate to the `s2Member Options` panel for configuration details.
37
 
38
- ***Special instructions for WordPress® MU:** If you're installing this plugin on WordPress® MU, and you run a Blog Farm ( e.g. you give away free blogs to the public ), you should create a file in this plugin's directory, and name it: `wpmu.farm`. When this plugin is running under WordPress® MU, and that file ( `wpmu.farm` ) is present, the plugin will disable PHP code evaluation on data provided by the user, and it will tell the plugin to mutate itself ( including its menus ) for compatiblity with public Blog Farms. You don't need to do this unless you run a public Blog Farm. If you're running the standard version of WordPress®, or you run WordPress® MU to host your own sites, you can safely skip this step.*
39
-
40
- ***Security On WordPress® MU Blog Farms:** This plugin is currently released as NOT having compatiblity with MU Blog Farms. This is because s2Member provides a configuration panel for protected file downloads, and also a programming API that makes PHP Constants and other routines available to advanced users. For these reasons, it is not a good idea to make s2Member available for use within a public Blog Farm. That being said, if you want to use the `wpmu.farm` file & tweak the code a little, you might be able to tune things in. -- If you're running the standard version of WordPress®, or you run WordPress® MU to host your own sites, you can safely ignore this warning.*
41
-
42
  == Description ==
43
 
44
  s2Member is a robust/powerful ( and free ) membership management system for WordPress®. s2Member integrates seamlessly with PayPal® ( very easy ), and fully supports recurring billing, with the ability to track affiliate commissions on a recurring basis. s2Member supports custom Pages for registration ( including Custom Registration Fields ), account access, and a whole lot more.
45
 
46
  s2Member supports up to four primary Membership Levels, and unlimited Custom Capability Packages. This allows you to create an unlimited number of Membership Packages, all with different Capabilities and prices. You can label your primary Membership Levels anything you like. The defaults are Bronze, Silver, Gold, and Platinum.
47
 
48
- s2Member allows you to protect Pages, Posts, Tags, Categories, URIs, URI word fragments, Single-Page Access, and even portions of content within Pages/Posts/themes/plugins. Everything is configurable through the s2Member Options Panel. This makes s2Member VERY easy to integrate into any WordPress®-powered site. With s2Member, you can also protect downloadable files, using special restrictions on how many downloads can occur within a certain amount of time; all based on Membership Level.
49
 
50
  Each Membership Level can have different restrictions, and you could even integrate Conditionals within your content based on Member Level. Advanced code samples are provided under `s2Member -> API Scripting -> Advanced Conditionals`. s2Member has been fully integrated with the Roles &amp; Capabilities that are already built into WordPress®. No new tables :-) It is designed to be completely seamless, without code bloat. We've carefully structured the entire framework, in order to maximize s2Member's ability to operate with other plugins installed. For instance, s2Member is compatible with BuddyPress!
51
 
52
- New! - Now you can sell Single-Page Access ( membership not required ), using "Buy Now" buttons. Further details are provided under `s2Member -> PayPal® Buttons`.
53
 
54
  == Screenshots ==
55
 
@@ -76,33 +71,70 @@ No, s2Member has been fully integrated with the Roles &amp; Capabilities that ar
76
  Yes, it can even generate your PayPal® Subscription Buttons for you. Everything is fully integrated. You even get to create your own Pages within WordPress® to handle Membership Options, the Login Welcome Page, etc. For advanced webmasters, there are scripting techniques that are documented as well. These will help you further develop your site and tailor it to meet your specific needs. s2Member API Scripting is NOT required however.
77
 
78
  = How many Membership Levels are supported? =
79
- s2Member supports up to 4 Primary Membership Levels, and unlimited Custom Capabilities. This allows you to create an unlimited number of Membership Packages, all with different Capabilities and prices. You can label your Membership Levels anything you like. The defaults are Bronze, Silver, Gold, Platinum. s2Member also makes it possible to sell an unlimited number of Single-Page Access Links using "Buy Now" buttons. Further details are provided under `s2Member -> PayPal® Buttons`.
80
 
81
  = Does s2Member utilize the PayPal® IPN system? =
82
- Yes, s2Member supports automation of account activation, welcome emails, confirmations, renewals, de-activation, refunds, etc. The integration with PayPal® is seamless. s2Member even provides API Notifications, which are an added layer of functionality. These are not to be confused with the IPN service. s2Member API Notifications make it easier to integrate back-office routines, affiliate programs, list servers, or any other 3rd-party application that should react to certain events.
83
 
84
  = Does s2Member support PayPal® PDT/Auto-Return? =
85
  Yes, s2Member will work with PayPal® Auto-Return/PDT (Payment Data Transfer) `On`, and also with Auto-Return/PDT `Off`. If you enable Auto-Return, you MUST also enable PDT and supply s2Member with your Identity Token. If one is enabled, the other must also be enabled; and vice-versa. There is a place to enter your PayPal® Identity Token for PDT under `s2Member -> PayPal® Options`.
86
 
87
  = How does s2Member protect content from public access? =
88
- s2Member allows you to protect Pages, Posts, Tags, Categories, URIs, URI word fragments, URI replacement codes for BuddyPress, Single-Page Access ( Buy Now! ), and even portions of content within Pages/Posts/themes/plugins using Advanced Conditionals. Everything is configurable through the s2Member Options Panel. This makes s2Member VERY easy to integrate into any WordPress®-powered site. With s2Member, you can also protect downloadable files, using special restrictions on how many downloads can occur within a certain amount of time. Each Membership Level can have different restrictions ( even Custom Capability Packages ). You can also integrate Conditionals within your content based on Member Level or Capabilities. Advanced code samples are provided under `s2Member -> API Scripting -> Advanced Conditionals`.
89
 
90
  = Does s2Member provide an API that I can connect to? =
91
  Yes, s2Member provides many *Advanced Scripting* techniques that are fully documented within its Option Panels. Code samples are provided for everything. There are several API functions that you can use, along with s2Member API Constants. This allows you to access many parts of its functionality, as well as specific Member information. Theme designers are welcome to integrate their themes/plugins with s2Member using the code samples that we provide under `s2Member -> API Scripting`. s2Member even provides API Notifications, which are an added layer of functionality. These are not to be confused with the IPN service. s2Member API Notifications make it easier to integrate back-office routines, affiliate programs, list servers, or any other 3rd-party application that should react to certain events.
92
 
93
  = Is s2Member compatible with Quick Cache or WP Super Cache? =
94
- Yes, there were some bugs in the beginning, but they have been fixed now. Both Quick Cache and WP Super Cache will remain compatible with s2Member. We have integrated two internal constants that prevent these plugins from caching important Members Only areas of your site, no matter what your cache configuration might be. The two Constants are: `DONOTCACHEPAGE` and `QUICK_CACHE_ALLOWED = false`. We recommend Quick Cache over WP Super Cache simply because we actually developed Quick Cache and we have done more extensive testing with the s2Member/Quick-Cache combination.
95
 
96
  = Is s2Member compatible with the BuddyPress plugin for WordPress? =
97
  Yes it is. In fact, we must say... the s2Member/BuddyPress combination is just awesome. These two plugins running together make all sorts of things possible.
98
 
 
 
 
 
 
 
99
  = Where can I download older versions of s2Member? =
100
  Archived releases of s2Member are maintained [here](http://wordpress.org/extend/plugins/s2member/download/).
101
 
 
 
 
 
 
102
  == Changelog ==
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  = 2.9.4 =
105
- * Bug fix in %%current_user_login%% for Special Redirection URLs. Was not processing correctly. This has been resolved in 2.9.4+.
106
  * Bug fix in AWeber®/MailChimp® integration for Free Subscriber registrations. Specifically, those originating from the front-end.
107
  * Extra security hardening. `MCRYPT_RIJNDAEL_256 / CBC` now being utilized in Registration Access Cookies.
108
  * New feature. s2Member now supports a custom Double Opt-In Checkbox for its List Server integrations. See `s2Member -> API List Servers -> Double Opt-In`. This is also compatible with BuddyPress registration forms.
1
  === s2Member ( Membership w/ PayPal® Integration ) also works w/ BuddyPress ===
2
 
3
+ Version: 3.0
4
+ Stable tag: 3.0
5
  Framework: WS-P-2.1
6
 
7
  WordPress Compatible: yes
8
  BuddyPress Compatible: yes
9
+ WP-Multisite Compatible: soon
 
10
 
11
  Tested up to: 3.0
12
  Requires at least: 2.8.4
34
  2. Activate the plugin through the `Plugins` menu in WordPress®.
35
  3. Navigate to the `s2Member Options` panel for configuration details.
36
 
 
 
 
 
37
  == Description ==
38
 
39
  s2Member is a robust/powerful ( and free ) membership management system for WordPress®. s2Member integrates seamlessly with PayPal® ( very easy ), and fully supports recurring billing, with the ability to track affiliate commissions on a recurring basis. s2Member supports custom Pages for registration ( including Custom Registration Fields ), account access, and a whole lot more.
40
 
41
  s2Member supports up to four primary Membership Levels, and unlimited Custom Capability Packages. This allows you to create an unlimited number of Membership Packages, all with different Capabilities and prices. You can label your primary Membership Levels anything you like. The defaults are Bronze, Silver, Gold, and Platinum.
42
 
43
+ s2Member allows you to protect Pages, Posts, Tags, Categories, URIs, URI word fragments, URI replacement codes for BuddyPress, Specific Post/Page "Buy Now" Access, and even portions of content within Pages/Posts/themes/plugins. Everything is configurable through the s2Member Options Panel. This makes s2Member VERY easy to integrate into any WordPress®-powered site. With s2Member, you can also protect downloadable files, using special restrictions on how many downloads can occur within a certain amount of time; all based on Membership Level.
44
 
45
  Each Membership Level can have different restrictions, and you could even integrate Conditionals within your content based on Member Level. Advanced code samples are provided under `s2Member -> API Scripting -> Advanced Conditionals`. s2Member has been fully integrated with the Roles &amp; Capabilities that are already built into WordPress®. No new tables :-) It is designed to be completely seamless, without code bloat. We've carefully structured the entire framework, in order to maximize s2Member's ability to operate with other plugins installed. For instance, s2Member is compatible with BuddyPress!
46
 
47
+ New! - Now you can sell Specific Post/Page Access ( membership not required ), using "Buy Now" buttons. You can even package multiple Posts/Pages together into one "Buy Now" transaction. Further details are provided under `s2Member -> PayPal® Buttons`.
48
 
49
  == Screenshots ==
50
 
71
  Yes, it can even generate your PayPal® Subscription Buttons for you. Everything is fully integrated. You even get to create your own Pages within WordPress® to handle Membership Options, the Login Welcome Page, etc. For advanced webmasters, there are scripting techniques that are documented as well. These will help you further develop your site and tailor it to meet your specific needs. s2Member API Scripting is NOT required however.
72
 
73
  = How many Membership Levels are supported? =
74
+ s2Member supports up to 4 Primary Membership Levels, and unlimited Custom Capabilities. This allows you to create an unlimited number of Membership Packages, all with different Capabilities and prices. You can label your Membership Levels anything you like. The defaults are Bronze, Silver, Gold, Platinum. s2Member also makes it possible to sell an unlimited number of Specific Post/Page Access Links using "Buy Now" buttons. Further details are provided under `s2Member -> PayPal® Buttons`.
75
 
76
  = Does s2Member utilize the PayPal® IPN system? =
77
+ Yes, s2Member supports automation of account activation, welcome emails, confirmations, renewals, de-activation, refunds, etc. The integration with PayPal® is seamless. s2Member even provides API Notifications, which are an added layer of functionality. These are not to be confused with the IPN service. s2Member API Notifications make it easier to integrate back-office routines, affiliate programs, list servers, or any other 3rd-party applications that should react to certain events.
78
 
79
  = Does s2Member support PayPal® PDT/Auto-Return? =
80
  Yes, s2Member will work with PayPal® Auto-Return/PDT (Payment Data Transfer) `On`, and also with Auto-Return/PDT `Off`. If you enable Auto-Return, you MUST also enable PDT and supply s2Member with your Identity Token. If one is enabled, the other must also be enabled; and vice-versa. There is a place to enter your PayPal® Identity Token for PDT under `s2Member -> PayPal® Options`.
81
 
82
  = How does s2Member protect content from public access? =
83
+ s2Member allows you to protect Pages, Posts, Tags, Categories, URIs, URI word fragments, URI replacement codes for BuddyPress, Specific Post/Page Access ( Buy Now! ), and even portions of content within Pages/Posts/themes/plugins using Advanced Conditionals. Everything is configurable through the s2Member Options Panel. This makes s2Member VERY easy to integrate into any WordPress®-powered site. With s2Member, you can also protect downloadable files, using special restrictions on how many downloads can occur within a certain amount of time. Each Membership Level can have different restrictions ( even Custom Capability Packages ). You can also integrate Conditionals within your content based on Member Level or Capabilities. Advanced code samples are provided under `s2Member -> API Scripting -> Advanced Conditionals`.
84
 
85
  = Does s2Member provide an API that I can connect to? =
86
  Yes, s2Member provides many *Advanced Scripting* techniques that are fully documented within its Option Panels. Code samples are provided for everything. There are several API functions that you can use, along with s2Member API Constants. This allows you to access many parts of its functionality, as well as specific Member information. Theme designers are welcome to integrate their themes/plugins with s2Member using the code samples that we provide under `s2Member -> API Scripting`. s2Member even provides API Notifications, which are an added layer of functionality. These are not to be confused with the IPN service. s2Member API Notifications make it easier to integrate back-office routines, affiliate programs, list servers, or any other 3rd-party application that should react to certain events.
87
 
88
  = Is s2Member compatible with Quick Cache or WP Super Cache? =
89
+ Yes, there were some bugs in the beginning, but they have been fixed now. Both Quick Cache and WP Super Cache will remain compatible with s2Member. We have integrated two internal Constants that prevent these plugins from caching important Members Only areas of your site, no matter what your cache configuration might be. The two Constants are: `DONOTCACHEPAGE` and `QUICK_CACHE_ALLOWED = false`. We recommend Quick Cache over WP Super Cache though; simply because we actually developed Quick Cache, and we've done more extensive testing with the s2Member/Quick-Cache combination.
90
 
91
  = Is s2Member compatible with the BuddyPress plugin for WordPress? =
92
  Yes it is. In fact, we must say... the s2Member/BuddyPress combination is just awesome. These two plugins running together make all sorts of things possible.
93
 
94
+ = How does s2Member know when to demote a paid Member to a Free Subscriber? =
95
+ s2Member uses its built-in Auto-EOT System ( new ). EOT = End Of Term. Whenever you generate a PayPal® Button with s2Member, you'll configure a length for the Subscription. Depending on the type of Subscription you choose ( recurring, non-recurring, lifetime, or fixed-term ); s2Member will either use PayPal's IPN/`subscr_cancel,subscr_eot` notices, or it will set an Automatic EOT Time, which is processed automatically by s2Member via WP_Cron. For each Member, you can also override the EOT Time, by forcing a specific expiration date. To manually adjust the EOT Time for a specific Member, go to: `WordPress® -> Users`, and click the Edit link next the Member you want to work on.
96
+
97
+ = How can I see more of what's going on behind-the-scene? =
98
+ s2Member comes with two very sophisticated logging systems. One for its PayPal® IPN communications ( and resulting actions ). The other logs Return-Data processing. You can enable them both, by going to: `s2Member -> PayPal® Options -> Account Details -> Logging`.
99
+
100
  = Where can I download older versions of s2Member? =
101
  Archived releases of s2Member are maintained [here](http://wordpress.org/extend/plugins/s2member/download/).
102
 
103
+ == Upgrade Notice ==
104
+
105
+ = 3.0 =
106
+ Upgrade highly recommended. After upgrading, go to: `s2Member -> PayPal® Options -> EOT Behavior` to enable the Auto-EOT System ( new ). For full details, please read the Changelog.
107
+
108
  == Changelog ==
109
 
110
+ = 3.0 =
111
+ * Naming convention change. s2Member's Single-Page Access, is now referred to as "Specific Post/Page Access". The reason for this will become obvious after reading through some of the other changes in this version. Among other things, "Posts" are now supported, instead of just Pages. Custom "Post-Types" are also supported now. Custom Post-Types are coming in WordPress® 3.0+. WordPress® 3.0 is scheduled for official release in May 2010.
112
+ * Specific Post/Page Access. s2Member now supports "Specific Post/Page Packages" too ( optional ). You can choose a "Leading" Post/Page, and also include "Additional" Posts/Pages. Customers will still land on your Leading Post/Page; BUT, they'll ALSO have access to any Additional Posts/Pages you've packaged together into one transaction. See: `s2Member -> PayPal® Buttons -> Specific Post/Page Buttons` for further details.
113
+ * Fixed-Term Buy Now Access. s2Member now supports Buy Now Access with fixed term lengths. In previous versions of s2Member, it was possible to create a Buy Now Button for Lifetime Membership Access, but now you can create Buy Now Buttons for specific time periods. Anything from 1 day, up to 5 years. The Lifetime option is also still available.
114
+ * Improvement. Registration Configuration routines have been re-organized for a higher level of compatibility across a wide array of s2Member configurations. No functionality changes here, just smarter configuration routines in `ws_plugin__s2member_configure_user_registration()`. This will make s2Member even more compatible with other plugins.
115
+ * Tracking Codes. s2Member has improved the way in which Tracking Codes are injected after returning from PayPal®. For full details, see: `s2Member -> API Tracking -> Signup Tracking Codes`. s2Member also supports Tracking Codes for Specific Post/Page Access now. Some additional replacement codes are also available through s2Member's Tracking API.
116
+ * AWeber® integration. s2Member now sends AWeber® some additional details, including: `EMail Address, First Name, Last Name, Full Name, IP Address, and Membership Level`. You can map these fields using a Custom Email Parser for AWeber® - if you wish to. Otherwise, the default "PayPal® Parser" for AWeber® will do fine. Please see: `s2Member -> API List Servers -> AWeber®` for full details.
117
+ * Security fix. Although unlikely, it was possible for a Site Administrator, testing extensively in the Sandbox; to perform a Subscription Modification while logged in as an Administrator; or an (Editor/Author/Contributor). The result was that their account could have been upgraded to an s2Member Role, depending on Button Configuration. This ran the risk of a built-in WP Role being locked out of their account. If this happended to you in a previous version of s2Member, please read [this article](http://codex.wordpress.org/Resetting_Your_Password) for assistance. Additional security routines have been added to prevent s2Member from EVER being able to modify an account belonging to any Administrator/Editor/Author/Contributor, under ANY circumstance.
118
+ * Typo auto-correction. A typo in the default Email Confirmation template for Specific Post/Page Access, which was first introduced in v2.8.7, and later corrected in v2.8.8 ( `%%sp_access_url%%` ). The incorrect value ( `%%access_url%%` ) was lingering if v2.8.7 was installed at some point in the past. s2Member v3.0 auto-corrects this typo ( should be `%%sp_access_url%%` ), just in case it still exists from a prior installation of s2Member v2.8.7.
119
+ * PayPal® Buttons. The Shortcode format for PayPal® Buttons, now supports a new attribute: `image="default"`. This can be changed to a full URL, pointing to a custom image of your own; instead of the default PayPal® image. This works for all types of PayPal® Buttons, including Member Levels 1-4, Cancellations, Modifications; and even Specific Post/Page Access Buttons.
120
+ * Registration Form. s2Member now makes the Registration Form available to any Site Administrator who is logged-in, even when `Allow Free Subscribers` is set to `false`. This makes the Registration Form easier to test during configuration; and it prevents confusion for site owners that are new to the s2Member plugin. This will NOT affect the functionality of s2Member otherwise, and should have NO impact on existing installations of s2Member.
121
+ * Specific Post/Page Access. s2Member now uses Specific Post/Page sessions ( i.e. cookies ). After clicking through to a Specific Post/Page, using a Specific Post/Page Access Link ( `%%sp_access_url%%` ) via email; the Customer is now authenticated for that specific Post/Page, using cookies. This allows the Customer to navigate through other areas of your site, and later return to the Specific Post/Page they paid for, without being forced to re-enter the Specific Post/Page with an encrypted link all over again. This does NOT change Specific Post/Page functionality, it just makes your site more user-friendly to Customers. They won't have to keep going back to their email to find their Access Link all the time. They click an Access Link once, then they're authenticated by cookies until their access expires ( based on your configuration ).
122
+ * References to the WordPress® function `human_time_diff()` have been replaced with an improved function: `ws_plugin__s2member_approx_time_difference()`; supporting human time differences in minutes, hours, days, weeks, months, years.
123
+ * References to s2Member's `append_query` function have been removed in favor of the WordPress® native function `add_query_arg()`. This was a redundant function, because WordPress® already provides this capability in its core.
124
+ * Bug fix. Missing admin APIs in `paypal-notify.inc.php`. This was causing an unknown function error `wp_delete_user()` on some s2Member installations; depending on the configuration. This has been corrected in v3.0.
125
+ * Optimized Post, Page, Tag, Category, and URI Level Access routines. Stress testing s2Member revealed some minor performance issues. Nothing major, but s2Member v3.0 has been further optimized to reduce CPU time.
126
+ * Custom Post-Types are now supported by s2Member Post Level Access Restrictions. Custom Post-Types are coming in WordPress® 3.0+. WordPress® 3.0 is scheduled for official release in May 2010.
127
+ * Notes field. s2Member now has a Notes field available for each account. See: `WordPress® -> Users -> Edit User`. This allows you to keep a list of Notations related to specific accounts.
128
+ * IP Access Restrictions. As with any membership system, it is possible for one Member to signup, and then share their Username or Access Links with someone else. s2Member now provides protection against this. See: `s2Member -> General Options -> IP Access Restrictions` for full details and configuration options.
129
+ * EOT demotions. Whenever s2Member demotes a Member to a Free Subscriber in response to an EOT event, s2Member now leaves a Note on the account, indicating the date/time the demotion occurred.
130
+ * EOT bug fix &amp; improvements. ( 2010 PayPal® accounts ). EOT = End Of Term. s2Member has been updated to support newer PayPal® accounts ( those opened after Oct 15th, 2009 ). Newer PayPal® accounts do NOT send an IPN/`subscr_eot` in all cases. This has been reported to PayPal® by several developers. At any rate, s2Member can deal with this gracefully now, by keeping a record of payments/periods/changes, and monitoring other signals sent by PayPal®. This allows s2Member to take control of the situation, at the appropriate time, using s2Member's built-in Auto-EOT System ( new ). The communication from PayPal® -> s2Member is seamless ( once again ); even in PayPal® accounts created after October 15th, 2009. These changes will NOT negatively effect existing installations of s2Member. If anything, it will improve your experience. More importantly, if your PayPal® account was established in 2010, you will definitely want to upgrade to s2Member v3.0+.
131
+
132
+ s2Member's Auto-EOT System has been integrated in favor of reliance on PayPal®. That is, s2Member no longer relies solely on `subscr_eot` responses; which is a good thing. The new Auto-EOT System, also makes it possible to set a manual EOT Time for each Member. Whenever you edit a Member, you'll see a new field ( `Automatic EOT Time` ) where you can override s2Member's decision, using a specific date/time that you supply. This is optional, but very powerful. In other words, you can now have a manual expiration date that does NOT have to be tied to a PayPal® Subscription.
133
+
134
+ Important: If you're upgrading from a previous version of s2Member, please enable s2Member's EOT System after you upgrade. Go to: `s2Member -> PayPal® Options -> EOT Behavior`. Enable the EOT System and click Save. That's it!
135
+
136
  = 2.9.4 =
137
+ * Bug fix in `%%current_user_login%%` for Special Redirection URLs. Was not processing correctly. This has been resolved in 2.9.4+.
138
  * Bug fix in AWeber®/MailChimp® integration for Free Subscriber registrations. Specifically, those originating from the front-end.
139
  * Extra security hardening. `MCRYPT_RIJNDAEL_256 / CBC` now being utilized in Registration Access Cookies.
140
  * New feature. s2Member now supports a custom Double Opt-In Checkbox for its List Server integrations. See `s2Member -> API List Servers -> Double Opt-In`. This is also compatible with BuddyPress registration forms.
s2member.php CHANGED
@@ -9,16 +9,15 @@ along with this software. In the main directory, see: /licensing/
9
  If not, see: <http://www.gnu.org/licenses/>.
10
  */
11
  /*
12
- Version: 2.9.4
13
- Stable tag: 2.9.4
14
  Framework: WS-P-2.1
15
 
16
  WordPress Compatible: yes
17
  BuddyPress Compatible: yes
18
- WordPress MU Compatible: soon
19
- MU Blog Farm Compatible: soon
20
 
21
- Tested up to: 2.9
22
  Requires at least: 2.8.4
23
  Requires: WordPress® 2.8.4+, PHP 5.2+
24
 
9
  If not, see: <http://www.gnu.org/licenses/>.
10
  */
11
  /*
12
+ Version: 3.0
13
+ Stable tag: 3.0
14
  Framework: WS-P-2.1
15
 
16
  WordPress Compatible: yes
17
  BuddyPress Compatible: yes
18
+ WP-Multisite Compatible: soon
 
19
 
20
+ Tested up to: 3.0
21
  Requires at least: 2.8.4
22
  Requires: WordPress® 2.8.4+, PHP 5.2+
23