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

Version Description

= v131025 = (Maintenance Release) Upgrade immediately.

Download this release

Release Info

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

Code changes from version 130816 to 131025

Files changed (143) hide show
  1. checksum.txt +1 -1
  2. images/add-icon.fla +0 -0
  3. images/arrow-down-icon.fla +0 -0
  4. images/arrow-up-icon.fla +0 -0
  5. images/bg.fla +0 -0
  6. images/brand-bg.fla +0 -0
  7. images/brand-bg.png +0 -0
  8. images/brand-dark.fla +0 -0
  9. images/brand-donations.fla +0 -0
  10. images/brand-favicon.fla +0 -0
  11. images/brand-favicon.png +0 -0
  12. images/brand-gradient-bg.fla +0 -0
  13. images/brand-icon.fla +0 -0
  14. images/brand-installation.fla +0 -0
  15. images/brand-kb.pspimage +0 -0
  16. images/brand-light.fla +0 -0
  17. images/brand-support.fla +0 -0
  18. images/brand-support.png +0 -0
  19. images/brand-tools.fla +0 -0
  20. images/brand-updates.fla +0 -0
  21. images/brand-upsell-pro.fla +0 -0
  22. images/brand-videos.fla +0 -0
  23. images/brand-xlink.fla +0 -0
  24. images/large-icon.fla +0 -0
  25. images/logo.fla +0 -0
  26. images/wordpress-dark.fla +0 -0
  27. images/wordpress-light.fla +0 -0
  28. includes/classes/auto-eots.inc.php +1 -1
  29. includes/classes/brute-force.inc.php +3 -5
  30. includes/classes/cache.inc.php +1 -1
  31. includes/classes/catgs-sp.inc.php +1 -1
  32. includes/classes/catgs.inc.php +1 -1
  33. includes/classes/constants.inc.php +65 -65
  34. includes/classes/custom-reg-fields.inc.php +4 -4
  35. includes/classes/email-configs.inc.php +5 -5
  36. includes/classes/files-in.inc.php +121 -121
  37. includes/classes/files.inc.php +6 -6
  38. includes/classes/installation.inc.php +4 -4
  39. includes/classes/list-servers.inc.php +12 -12
  40. includes/classes/login-checks.inc.php +209 -0
  41. includes/classes/login-redirects-r.inc.php +27 -11
  42. includes/classes/login-redirects.inc.php +12 -28
  43. includes/classes/menu-pages.inc.php +30 -39
  44. includes/classes/meta-box-saves.inc.php +2 -2
  45. includes/classes/meta-box-security.inc.php +2 -2
  46. includes/classes/meta-boxes.inc.php +2 -2
  47. includes/classes/mms-patches.inc.php +6 -6
  48. includes/classes/no-cache.inc.php +1 -1
  49. includes/classes/op-notices.inc.php +7 -7
  50. includes/classes/option-forces.inc.php +3 -3
  51. includes/classes/pages-sp.inc.php +2 -2
  52. includes/classes/pages.inc.php +2 -2
  53. includes/classes/paypal-notify-in-cart.inc.php +3 -3
  54. includes/classes/paypal-notify-in-express-checkout.inc.php +3 -3
  55. includes/classes/paypal-notify-in-rec-profile-creation-w-level.inc.php +3 -3
  56. includes/classes/paypal-notify-in-send-money.inc.php +3 -3
  57. includes/classes/paypal-notify-in-sp-refund-reversal.inc.php +3 -3
  58. includes/classes/paypal-notify-in-subscr-modify-w-level.inc.php +4 -4
  59. includes/classes/paypal-notify-in-subscr-or-rp-cancellation-w-level.inc.php +3 -3
  60. includes/classes/paypal-notify-in-subscr-or-rp-eots-w-level.inc.php +6 -6
  61. includes/classes/paypal-notify-in-subscr-or-rp-payment-failed-w-level.inc.php +3 -3
  62. includes/classes/paypal-notify-in-subscr-or-rp-payment-w-level.inc.php +4 -4
  63. includes/classes/paypal-notify-in-subscr-or-wa-w-level.inc.php +5 -5
  64. includes/classes/paypal-notify-in-virtual-terminal.inc.php +3 -3
  65. includes/classes/paypal-notify-in-wa-ccaps-wo-level.inc.php +3 -3
  66. includes/classes/paypal-notify-in-web-accept-sp.inc.php +3 -3
  67. includes/classes/paypal-notify-in.inc.php +8 -8
  68. includes/classes/paypal-notify.inc.php +3 -3
  69. includes/classes/paypal-return-in-no-tx-data.inc.php +3 -3
  70. includes/classes/paypal-return-in-proxy-ty-email.inc.php +3 -3
  71. includes/classes/paypal-return-in-proxy-x-preview.inc.php +3 -3
  72. includes/classes/paypal-return-in-subscr-modify-w-level.inc.php +4 -4
  73. includes/classes/paypal-return-in-subscr-or-wa-w-level.inc.php +5 -5
  74. includes/classes/paypal-return-in-wa-ccaps-wo-level.inc.php +3 -3
  75. includes/classes/paypal-return-in-web-accept-sp.inc.php +3 -3
  76. includes/classes/paypal-return-in.inc.php +9 -9
  77. includes/classes/paypal-return.inc.php +3 -3
  78. includes/classes/paypal-utilities.inc.php +34 -34
  79. includes/classes/posts-sp.inc.php +2 -2
  80. includes/classes/posts.inc.php +2 -2
  81. includes/classes/ptags-sp.inc.php +1 -1
  82. includes/classes/ptags.inc.php +1 -1
  83. includes/classes/querys.inc.php +8 -7
  84. includes/classes/register-access.inc.php +1 -1
  85. includes/classes/registration-times.inc.php +4 -4
  86. includes/classes/registrations.inc.php +8 -8
  87. includes/classes/roles-caps.inc.php +5 -5
  88. includes/classes/ruris-sp.inc.php +1 -1
  89. includes/classes/ruris.inc.php +1 -1
  90. includes/classes/sc-paypal-button-e.inc.php +11 -11
  91. includes/classes/sc-paypal-button-in.inc.php +7 -7
  92. includes/classes/security.inc.php +3 -3
  93. includes/classes/sp-access.inc.php +1 -1
  94. includes/classes/ssl.inc.php +1 -1
  95. includes/classes/systematics-sp.inc.php +12 -12
  96. includes/classes/systematics.inc.php +10 -10
  97. includes/classes/tracking-codes.inc.php +3 -3
  98. includes/classes/translations.inc.php +1 -1
  99. includes/classes/user-access.inc.php +2 -2
  100. includes/classes/user-deletions.inc.php +3 -3
  101. includes/classes/user-new-in.inc.php +4 -4
  102. includes/classes/user-notes.inc.php +2 -2
  103. includes/classes/user-securities.inc.php +3 -3
  104. includes/classes/users-list-in.inc.php +9 -9
  105. includes/classes/users-list.inc.php +2 -2
  106. includes/classes/utilities.inc.php +4 -4
  107. includes/classes/utils-captchas.inc.php +1 -1
  108. includes/classes/utils-conds.inc.php +5 -5
  109. includes/classes/utils-cur.inc.php +1 -1
  110. includes/classes/utils-dirs.inc.php +5 -5
  111. includes/classes/utils-encryption.inc.php +1 -1
  112. includes/classes/utils-gets.inc.php +4 -3
  113. includes/classes/utils-logs.inc.php +22 -22
  114. includes/classes/utils-s2o.inc.php +7 -7
  115. includes/classes/utils-time.inc.php +2 -2
  116. includes/classes/utils-urls.inc.php +5 -5
  117. includes/classes/utils-users.inc.php +25 -25
  118. includes/classes/wp-footer.inc.php +2 -2
  119. includes/codes.inc.php +1 -1
  120. includes/externals/mailchimp/nc-mcapi.inc.php +2 -2
  121. includes/externals/markdown/nc-markdown.inc.php +2 -2
  122. includes/functions/api-functions.inc.php +84 -84
  123. includes/functions/pluggables.inc.php +1 -1
  124. includes/hooks.inc.php +7 -1
  125. includes/jquery/jquery.json-ps/jquery.json-ps.js +1 -1
  126. includes/jquery/jquery.sprintf/jquery.sprintf.js +1 -1
  127. includes/jquery/jquery.ui-effects/jquery.ui-effects.js +1 -1
  128. includes/menu-pages/api-ops.inc.php +23 -23
  129. includes/menu-pages/down-ops.inc.php +104 -102
  130. includes/menu-pages/els-ops.inc.php +23 -23
  131. includes/menu-pages/gen-ops.inc.php +30 -30
  132. includes/menu-pages/info.inc.php +1 -1
  133. includes/menu-pages/integrations.inc.php +14 -14
  134. includes/menu-pages/js-c-warning.inc.php +2 -2
  135. includes/menu-pages/logs.inc.php +23 -23
  136. includes/menu-pages/menu-pages-s-min.js +1 -1
  137. includes/menu-pages/menu-pages-s.js +9 -9
  138. includes/menu-pages/menu-pages.css +17 -13
  139. includes/menu-pages/menu-pages.js +1 -1
  140. includes/menu-pages/mms-ops.inc.php +13 -13
  141. includes/menu-pages/paypal-buttons.inc.php +50 -50
  142. includes/menu-pages/paypal-ops.inc.php +59 -59
  143. includes/menu-pages/res-ops.inc.php +66 -16
checksum.txt CHANGED
@@ -1 +1 @@
1
- a1483e3b04ff24591ddc65fac0e7b361
1
+ 14706c88153810667238a28523add0a9
images/add-icon.fla DELETED
Binary file
images/arrow-down-icon.fla DELETED
Binary file
images/arrow-up-icon.fla DELETED
Binary file
images/bg.fla DELETED
Binary file
images/brand-bg.fla DELETED
Binary file
images/brand-bg.png CHANGED
Binary file
images/brand-dark.fla DELETED
Binary file
images/brand-donations.fla DELETED
Binary file
images/brand-favicon.fla DELETED
Binary file
images/brand-favicon.png CHANGED
Binary file
images/brand-gradient-bg.fla DELETED
Binary file
images/brand-icon.fla DELETED
Binary file
images/brand-installation.fla DELETED
Binary file
images/brand-kb.pspimage DELETED
Binary file
images/brand-light.fla DELETED
Binary file
images/brand-support.fla DELETED
Binary file
images/brand-support.png CHANGED
Binary file
images/brand-tools.fla DELETED
Binary file
images/brand-updates.fla DELETED
Binary file
images/brand-upsell-pro.fla DELETED
Binary file
images/brand-videos.fla DELETED
Binary file
images/brand-xlink.fla DELETED
Binary file
images/large-icon.fla DELETED
Binary file
images/logo.fla DELETED
Binary file
images/wordpress-dark.fla DELETED
Binary file
images/wordpress-light.fla DELETED
Binary file
includes/classes/auto-eots.inc.php CHANGED
@@ -113,7 +113,7 @@ if (!class_exists ("c_ws_plugin__s2member_auto_eots"))
113
  {
114
  $per_process = apply_filters ("ws_plugin__s2member_auto_eot_system_per_process", $per_process, get_defined_vars ());
115
 
116
- if (is_array ($eots = $wpdb->get_results ("SELECT `user_id` AS `ID` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = '" . $wpdb->prefix . "s2member_auto_eot_time' AND `meta_value` != '' AND `meta_value` <= '" . $wpdb->escape (strtotime ("now")) . "' LIMIT " . $per_process)))
117
  {
118
  foreach /* Go through the array of EOTS. We need to (demote|delete) each of them. */ ($eots as $eot)
119
  {
113
  {
114
  $per_process = apply_filters ("ws_plugin__s2member_auto_eot_system_per_process", $per_process, get_defined_vars ());
115
 
116
+ if (is_array ($eots = $wpdb->get_results ("SELECT `user_id` AS `ID` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = '" . $wpdb->prefix . "s2member_auto_eot_time' AND `meta_value` != '' AND `meta_value` <= '" . esc_sql(strtotime ("now")) . "' LIMIT " . $per_process)))
117
  {
118
  foreach /* Go through the array of EOTS. We need to (demote|delete) each of them. */ ($eots as $eot)
119
  {
includes/classes/brute-force.inc.php CHANGED
@@ -82,13 +82,11 @@ if (!class_exists ("c_ws_plugin__s2member_brute_force"))
82
 
83
  if (($max = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_failed_login_attempts"]))
84
  {
85
- $exp_secs = strtotime ("+" . apply_filters ("ws_plugin__s2member_track_failed_logins__exp_time", "30 minutes", get_defined_vars ())) - time ();
86
- // If you add Filters to this value, you should use a string that is compatible with PHP's strtotime() function.
87
-
88
- $about = c_ws_plugin__s2member_utils_time::approx_time_difference (time (), time () + $exp_secs);
89
-
90
  if ((int)get_transient ("s2m_ipr_" . md5 ("s2member_transient_failed_login_attempts_" . $_SERVER["REMOTE_ADDR"])) > $max)
91
  {
 
 
 
92
  $errors = new WP_Error ("incorrect_password", sprintf (_x ("Max failed logins. Please wait %s and try again.", "s2member-front", "s2member"), $about));
93
 
94
  foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
82
 
83
  if (($max = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_failed_login_attempts"]))
84
  {
 
 
 
 
 
85
  if ((int)get_transient ("s2m_ipr_" . md5 ("s2member_transient_failed_login_attempts_" . $_SERVER["REMOTE_ADDR"])) > $max)
86
  {
87
+ $exp_secs = strtotime ("+" . apply_filters ("ws_plugin__s2member_track_failed_logins__exp_time", "30 minutes", get_defined_vars ())) - time ();
88
+ // If you add Filters to this value, you should use a string that is compatible with PHP's strtotime() function.
89
+ $about = c_ws_plugin__s2member_utils_time::approx_time_difference (time (), time () + $exp_secs);
90
  $errors = new WP_Error ("incorrect_password", sprintf (_x ("Max failed logins. Please wait %s and try again.", "s2member-front", "s2member"), $about));
91
 
92
  foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
includes/classes/cache.inc.php CHANGED
@@ -90,7 +90,7 @@ if (!class_exists ("c_ws_plugin__s2member_cache"))
90
 
91
  $cache_needs_updating = /* Flag for cache update. */ true;
92
  }
93
- if /* Cache is also reset dynamically during back-end option updates. */ ($cache_needs_updating)
94
  {
95
  update_option ("ws_plugin__s2member_cache", $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["cache"]);
96
  }
90
 
91
  $cache_needs_updating = /* Flag for cache update. */ true;
92
  }
93
+ if /* Cache is also reset dynamically during back-end option updates. */ (isset($cache_needs_updating) && $cache_needs_updating)
94
  {
95
  update_option ("ws_plugin__s2member_cache", $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["cache"]);
96
  }
includes/classes/catgs-sp.inc.php CHANGED
@@ -47,7 +47,7 @@ if (!class_exists ("c_ws_plugin__s2member_catgs_sp"))
47
  {
48
  $cat_uri = /* Get a full valid URI for this Category. */ c_ws_plugin__s2member_utils_urls::parse_uri (get_category_link ($cat_id));
49
 
50
- if /* Do NOT touch WordPress® Systematics. */ (!c_ws_plugin__s2member_systematics_sp::is_wp_systematic_use_specific_page (null, $cat_uri))
51
  {
52
  $user = /* Current User's object. */(is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false;
53
 
47
  {
48
  $cat_uri = /* Get a full valid URI for this Category. */ c_ws_plugin__s2member_utils_urls::parse_uri (get_category_link ($cat_id));
49
 
50
+ if /* Do NOT touch WordPress Systematics. */ (!c_ws_plugin__s2member_systematics_sp::is_wp_systematic_use_specific_page (null, $cat_uri))
51
  {
52
  $user = /* Current User's object. */(is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false;
53
 
includes/classes/catgs.inc.php CHANGED
@@ -45,7 +45,7 @@ if (!class_exists ("c_ws_plugin__s2member_catgs"))
45
 
46
  if (!$excluded && is_category () && ($cat_id = get_query_var ("cat")) && ($cat_id = (int)$cat_id) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
47
  {
48
- if /* Do NOT touch WordPress® Systematics. This excludes all WordPress® Systematics. */ (!c_ws_plugin__s2member_systematics::is_wp_systematic_use_page ())
49
  {
50
  $user = /* Current User's object. */ (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false;
51
 
45
 
46
  if (!$excluded && is_category () && ($cat_id = get_query_var ("cat")) && ($cat_id = (int)$cat_id) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
47
  {
48
+ if /* Do NOT touch WordPress Systematics. This excludes all WordPress Systematics. */ (!c_ws_plugin__s2member_systematics::is_wp_systematic_use_page ())
49
  {
50
  $user = /* Current User's object. */ (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false;
51
 
includes/classes/constants.inc.php CHANGED
@@ -31,7 +31,7 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
31
  * Defines several API Constants for s2Member.
32
  *
33
  * These are also duplicated into the JavaScript API for s2Member.
34
- * Except for a few that would pose a security issue. Such as the PayPal® API Credentials;
35
  * those are NOT included in the JavaScript API.
36
  *
37
  * @package s2Member\API_Constants
@@ -323,7 +323,7 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
323
  define ("S2MEMBER_CURRENT_USER_SUBSCR_ID", ($c[] = (($user) ? (string)$subscr_id : "")));
324
  /**
325
  * The current User's Paid Subscription ID (when applicable);
326
- * otherwise, this will contain their WordPress® User ID.
327
  *
328
  * An empty string if NOT logged-in.
329
  *
@@ -908,7 +908,7 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
908
  if (!defined ("S2MEMBER_CURRENT_USER_REGISTRATION_IP"))
909
  define ("S2MEMBER_CURRENT_USER_REGISTRATION_IP", ($c[] = (($user) ? (string)$registration_ip : "")));
910
  /**
911
- * The current User's WordPress® User ID.
912
  *
913
  * This will be equal to `0` if NOT logged-in.
914
  *
@@ -1510,7 +1510,7 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
1510
  /**
1511
  * The URL, which logs the current User out of their account.
1512
  *
1513
- * This is the value provided by WordPress®. It's the same as using ``wp_logout_url()``.
1514
  *
1515
  * ———— Quick PHP Code Sample ————
1516
  * ```
@@ -1550,7 +1550,7 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
1550
  /**
1551
  * The URL, where a User can log into their account.
1552
  *
1553
- * This is the value provided by WordPress®. It's the same as using ``wp_login_url()``.
1554
  *
1555
  * ———— Quick PHP Code Sample ————
1556
  * ```
@@ -1833,7 +1833,7 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
1833
  if (!defined ("S2MEMBER_REG_EMAIL_FROM_EMAIL"))
1834
  define ("S2MEMBER_REG_EMAIL_FROM_EMAIL", ($c[] = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"]));
1835
  /**
1836
- * Full URL to PayPal® IPN handler, provided by s2Member.
1837
  *
1838
  * ———— Quick PHP Code Sample ————
1839
  * ```
@@ -1856,12 +1856,12 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
1856
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_RETURN_URL
1857
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_PDT_IDENTITY_TOKEN
1858
  *
1859
- * @see `Dashboard -› s2Member -› PayPal® Options -› IPN Integration`
1860
  */
1861
  if (!defined ("S2MEMBER_PAYPAL_NOTIFY_URL"))
1862
  define ("S2MEMBER_PAYPAL_NOTIFY_URL", ($c[] = (string)site_url ("/?s2member_paypal_notify=1")));
1863
  /**
1864
- * Full URL to PayPal® Auto-Return/PDT handler, provided by s2Member.
1865
  *
1866
  * ———— Quick PHP Code Sample ————
1867
  * ```
@@ -1884,12 +1884,12 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
1884
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_NOTIFY_URL
1885
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_PDT_IDENTITY_TOKEN
1886
  *
1887
- * @see `Dashboard -› s2Member -› PayPal® Options -› Auto-Return/PDT Integration`
1888
  */
1889
  if (!defined ("S2MEMBER_PAYPAL_RETURN_URL"))
1890
  define ("S2MEMBER_PAYPAL_RETURN_URL", ($c[] = (string)site_url ("/?s2member_paypal_return=1")));
1891
  /**
1892
- * PayPal® Business Email Address; as configured by the site owner.
1893
  *
1894
  * ———— Quick PHP Code Sample ————
1895
  * ```
@@ -1913,12 +1913,12 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
1913
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_PASSWORD
1914
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_SIGNATURE
1915
  *
1916
- * @see `Dashboard -› s2Member -› PayPal® Options -› Account Details`
1917
  */
1918
  if (!defined ("S2MEMBER_PAYPAL_BUSINESS"))
1919
  define ("S2MEMBER_PAYPAL_BUSINESS", ($c[] = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"]));
1920
  /**
1921
- * PayPal® endpoint domain (changes when Sandbox Mode is enabled).
1922
  *
1923
  * o In Sandbox Mode, this is: `www.sandbox.paypal.com`.
1924
  * o In Production Mode, this is: `www.paypal.com`.
@@ -1943,12 +1943,12 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
1943
  *
1944
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_ENDPOINT
1945
  *
1946
- * @see `Dashboard -› s2Member -› PayPal® Options -› Account Details`
1947
  */
1948
  if (!defined ("S2MEMBER_PAYPAL_ENDPOINT"))
1949
  define ("S2MEMBER_PAYPAL_ENDPOINT", ($c[] = (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")));
1950
  /**
1951
- * PayPal® API endpoint domain (changes when Sandbox Mode is enabled).
1952
  *
1953
  * o In Sandbox Mode, this is: `api-3t.sandbox.paypal.com`.
1954
  * o In Production Mode, this is: `api-3t.paypal.com`.
@@ -1973,12 +1973,12 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
1973
  *
1974
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_ENDPOINT
1975
  *
1976
- * @see `Dashboard -› s2Member -› PayPal® Options -› Account Details`
1977
  */
1978
  if (!defined ("S2MEMBER_PAYPAL_API_ENDPOINT"))
1979
  define ("S2MEMBER_PAYPAL_API_ENDPOINT", ($c[] = (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "api-3t.sandbox.paypal.com" : "api-3t.paypal.com")));
1980
  /**
1981
- * PayPal® API Username; as configured by the site owner.
1982
  *
1983
  * ———— Quick PHP Code Sample ————
1984
  * ```
@@ -2001,12 +2001,12 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
2001
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_PASSWORD
2002
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_SIGNATURE
2003
  *
2004
- * @see `Dashboard -› s2Member -› PayPal® Options -› Account Details`
2005
  */
2006
  if (!defined ("S2MEMBER_PAYPAL_API_USERNAME"))
2007
  define ("S2MEMBER_PAYPAL_API_USERNAME", ($c[] = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_username"]));
2008
  /**
2009
- * PayPal® API Password; as configured by the site owner.
2010
  *
2011
  * ———— Quick PHP Code Sample ————
2012
  * ```
@@ -2029,12 +2029,12 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
2029
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_USERNAME
2030
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_SIGNATURE
2031
  *
2032
- * @see `Dashboard -› s2Member -› PayPal® Options -› Account Details`
2033
  */
2034
  if (!defined ("S2MEMBER_PAYPAL_API_PASSWORD"))
2035
  define ("S2MEMBER_PAYPAL_API_PASSWORD", ($c[] = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_password"]));
2036
  /**
2037
- * PayPal® API Signature; as configured by the site owner.
2038
  *
2039
  * ———— Quick PHP Code Sample ————
2040
  * ```
@@ -2057,12 +2057,12 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
2057
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_USERNAME
2058
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_PASSWORD
2059
  *
2060
- * @see `Dashboard -› s2Member -› PayPal® Options -› Account Details`
2061
  */
2062
  if (!defined ("S2MEMBER_PAYPAL_API_SIGNATURE"))
2063
  define ("S2MEMBER_PAYPAL_API_SIGNATURE", ($c[] = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_signature"]));
2064
  /**
2065
- * PayPal® PDT Identity Token; as configured by the site owner.
2066
  *
2067
  * ———— Quick PHP Code Sample ————
2068
  * ```
@@ -2084,14 +2084,14 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
2084
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_RETURN_URL
2085
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_NOTIFY_URL
2086
  *
2087
- * @see `Dashboard -› s2Member -› PayPal® Options -› Auto-Return/PDT Integration`
2088
  */
2089
  if (!defined ("S2MEMBER_PAYPAL_PDT_IDENTITY_TOKEN"))
2090
  define ("S2MEMBER_PAYPAL_PDT_IDENTITY_TOKEN", ($c[] = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_identity_token"]));
2091
  /**
2092
- * PayPal® value for Payment Buttons with input name: `invoice`.
2093
  *
2094
- * This can be used to auto-fill the `invoice` value in PayPal® Button Codes, with a unique Code~IP combination.
2095
  * However, in cases where multiple Buttons are displayed on the same page, the alternative {@link s2Member\API_Functions\s2member_value_for_pp_inv()} function should be used instead.
2096
  *
2097
  * Note. This API Constant is excluded from the ``$c[]`` hash calculation used in the generation of {@link s2Member\API_Constants\WS_PLUGIN__S2MEMBER_API_CONSTANTS_MD5}.
@@ -2106,20 +2106,20 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
2106
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1}
2107
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1}
2108
  *
2109
- * They are used by the PayPal® Button Generator for s2Member.
2110
  *
2111
- * The `INV` value can be used to auto-fill the `invoice` for PayPal® Button Codes, with a unique Code~IP combination.
2112
  * However, in cases where multiple Buttons are displayed on the same page, the alternative {@link s2Member\API_Functions\s2member_value_for_pp_inv()} function should be used instead.
2113
  *
2114
  * The `ON0/OS0` values, are how s2Member identifies an existing Member *(and/or a Free Subscriber)*, who is already logged-in
2115
- * when they click a PayPal® Modification Button that was generated for you by s2Member's Button Generator.
2116
  *
2117
  * Instead of forcing a Member *(and/or a Free Subscriber)* to re-register for a new account,
2118
  * s2Member can identify their existing account, and update it; according to the modified terms in your Button Code.
2119
- * These three Button Code parameters: `on0`, `os0`, `modify`, work together in harmony. If you're using the Shortcode Format for PayPal® Buttons,
2120
  * you won't even see these, because they're added internally by the Shortcode processor.
2121
  *
2122
- * The `ON1/OS1` values, are used by s2Member to identify a Customer's IP Address through IPN communications with PayPal®.
2123
  *
2124
  * Anyway, these five API Constants are just documented here for clarity;
2125
  * you probably won't use any of these directly; the Button Generator pops them in.
@@ -2144,16 +2144,16 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
2144
  *
2145
  * @see s2Member\API_Functions\s2member_value_for_pp_inv()
2146
  *
2147
- * @see `Dashboard -› s2Member -› PayPal® Buttons`
2148
  */
2149
  if (!defined ("S2MEMBER_VALUE_FOR_PP_INV"))
2150
  define ("S2MEMBER_VALUE_FOR_PP_INV", uniqid () . "~" . S2MEMBER_CURRENT_USER_IP);
2151
  /**
2152
- * PayPal® value for Payment Buttons with input name: `on0`.
2153
  *
2154
- * Used in PayPal® Modification Buttons *(i.e. upgrades/downgrades)*.
2155
  *
2156
- * This auto-fills the `on0` value in PayPal® Button Codes. If a Button Code is presented to a logged-in Member,
2157
  * this will auto-fill the value for the `on0` input variable, with the string: "Referencing Customer ID".
2158
  * Otherwise, it will be set to a default value of: "Originating Domain".
2159
  *
@@ -2164,20 +2164,20 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
2164
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1}
2165
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1}
2166
  *
2167
- * They are used by the PayPal® Button Generator for s2Member.
2168
  *
2169
- * The `INV` value can be used to auto-fill the `invoice` for PayPal® Button Codes, with a unique Code~IP combination.
2170
  * However, in cases where multiple Buttons are displayed on the same page, the alternative {@link s2Member\API_Functions\s2member_value_for_pp_inv()} function should be used instead.
2171
  *
2172
  * The `ON0/OS0` values, are how s2Member identifies an existing Member *(and/or a Free Subscriber)*, who is already logged-in
2173
- * when they click a PayPal® Modification Button that was generated for you by s2Member's Button Generator.
2174
  *
2175
  * Instead of forcing a Member *(and/or a Free Subscriber)* to re-register for a new account,
2176
  * s2Member can identify their existing account, and update it; according to the modified terms in your Button Code.
2177
- * These three Button Code parameters: `on0`, `os0`, `modify`, work together in harmony. If you're using the Shortcode Format for PayPal® Buttons,
2178
  * you won't even see these, because they're added internally by the Shortcode processor.
2179
  *
2180
- * The `ON1/OS1` values, are used by s2Member to identify a Customer's IP Address through IPN communications with PayPal®.
2181
  *
2182
  * Anyway, these five API Constants are just documented here for clarity;
2183
  * you probably won't use any of these directly; the Button Generator pops them in.
@@ -2202,16 +2202,16 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
2202
  *
2203
  * @see s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS0
2204
  *
2205
- * @see `Dashboard -› s2Member -› PayPal® Buttons`
2206
  */
2207
  if (!defined ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0"))
2208
  define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0", ($c[] = ((S2MEMBER_CURRENT_USER_SUBSCR_OR_WP_ID) ? "Referencing Customer ID" : "Originating Domain")));
2209
  /**
2210
- * PayPal® value for Payment Buttons with input name: `os0`.
2211
  *
2212
- * Used in PayPal® Modification Buttons *(i.e. upgrades/downgrades)*.
2213
  *
2214
- * This auto-fills the `os0` value in PayPal® Button Codes. If a Button Code is presented to a logged-in Member,
2215
  * this will auto-fill the value for the `os0` input variable, with the value of {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_SUBSCR_OR_WP_ID}.
2216
  * Otherwise, it will be set to a default value of ``$_SERVER["HTTP_HOST"]`` *(the originating domain name)*.
2217
  *
@@ -2222,20 +2222,20 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
2222
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1}
2223
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1}
2224
  *
2225
- * They are used by the PayPal® Button Generator for s2Member.
2226
  *
2227
- * The `INV` value can be used to auto-fill the `invoice` for PayPal® Button Codes, with a unique Code~IP combination.
2228
  * However, in cases where multiple Buttons are displayed on the same page, the alternative {@link s2Member\API_Functions\s2member_value_for_pp_inv()} function should be used instead.
2229
  *
2230
  * The `ON0/OS0` values, are how s2Member identifies an existing Member *(and/or a Free Subscriber)*, who is already logged-in
2231
- * when they click a PayPal® Modification Button that was generated for you by s2Member's Button Generator.
2232
  *
2233
  * Instead of forcing a Member *(and/or a Free Subscriber)* to re-register for a new account,
2234
  * s2Member can identify their existing account, and update it; according to the modified terms in your Button Code.
2235
- * These three Button Code parameters: `on0`, `os0`, `modify`, work together in harmony. If you're using the Shortcode Format for PayPal® Buttons,
2236
  * you won't even see these, because they're added internally by the Shortcode processor.
2237
  *
2238
- * The `ON1/OS1` values, are used by s2Member to identify a Customer's IP Address through IPN communications with PayPal®.
2239
  *
2240
  * Anyway, these five API Constants are just documented here for clarity;
2241
  * you probably won't use any of these directly; the Button Generator pops them in.
@@ -2260,14 +2260,14 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
2260
  *
2261
  * @see s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0
2262
  *
2263
- * @see `Dashboard -› s2Member -› PayPal® Buttons`
2264
  */
2265
  if (!defined ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS0"))
2266
  define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS0", ($c[] = ((S2MEMBER_CURRENT_USER_SUBSCR_OR_WP_ID) ? S2MEMBER_CURRENT_USER_SUBSCR_OR_WP_ID : (string)$_SERVER["HTTP_HOST"])));
2267
  /**
2268
- * PayPal® value for Payment Buttons with input name: `on1`.
2269
  *
2270
- * This auto-fills the `on1` value in PayPal® Button Codes.
2271
  * This always contains the string: "Customer IP Address".
2272
  *
2273
  * These five API Constants are special.
@@ -2277,20 +2277,20 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
2277
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1}
2278
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1}
2279
  *
2280
- * They are used by the PayPal® Button Generator for s2Member.
2281
  *
2282
- * The `INV` value can be used to auto-fill the `invoice` for PayPal® Button Codes, with a unique Code~IP combination.
2283
  * However, in cases where multiple Buttons are displayed on the same page, the alternative {@link s2Member\API_Functions\s2member_value_for_pp_inv()} function should be used instead.
2284
  *
2285
  * The `ON0/OS0` values, are how s2Member identifies an existing Member *(and/or a Free Subscriber)*, who is already logged-in
2286
- * when they click a PayPal® Modification Button that was generated for you by s2Member's Button Generator.
2287
  *
2288
  * Instead of forcing a Member *(and/or a Free Subscriber)* to re-register for a new account,
2289
  * s2Member can identify their existing account, and update it; according to the modified terms in your Button Code.
2290
- * These three Button Code parameters: `on0`, `os0`, `modify`, work together in harmony. If you're using the Shortcode Format for PayPal® Buttons,
2291
  * you won't even see these, because they're added internally by the Shortcode processor.
2292
  *
2293
- * The `ON1/OS1` values, are used by s2Member to identify a Customer's IP Address through IPN communications with PayPal®.
2294
  *
2295
  * Anyway, these five API Constants are just documented here for clarity;
2296
  * you probably won't use any of these directly; the Button Generator pops them in.
@@ -2315,14 +2315,14 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
2315
  *
2316
  * @see s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1
2317
  *
2318
- * @see `Dashboard -› s2Member -› PayPal® Buttons`
2319
  */
2320
  if (!defined ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1"))
2321
  define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1", ($c[] = "Customer IP Address" /* Via $_SERVER["REMOTE_ADDR"] below. */));
2322
  /**
2323
- * PayPal® value for Payment Buttons with input name: `os1`.
2324
  *
2325
- * This auto-fills the `os1` value in PayPal® Button Codes,
2326
  * with the Customer's IP Address, via ``$_SERVER["REMOTE_ADDR"]``.
2327
  *
2328
  * These five API Constants are special.
@@ -2332,20 +2332,20 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
2332
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1}
2333
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1}
2334
  *
2335
- * They are used by the PayPal® Button Generator for s2Member.
2336
  *
2337
- * The `INV` value can be used to auto-fill the `invoice` for PayPal® Button Codes, with a unique Code~IP combination.
2338
  * However, in cases where multiple Buttons are displayed on the same page, the alternative {@link s2Member\API_Functions\s2member_value_for_pp_inv()} function should be used instead.
2339
  *
2340
  * The `ON0/OS0` values, are how s2Member identifies an existing Member *(and/or a Free Subscriber)*, who is already logged-in
2341
- * when they click a PayPal® Modification Button that was generated for you by s2Member's Button Generator.
2342
  *
2343
  * Instead of forcing a Member *(and/or a Free Subscriber)* to re-register for a new account,
2344
  * s2Member can identify their existing account, and update it; according to the modified terms in your Button Code.
2345
- * These three Button Code parameters: `on0`, `os0`, `modify`, work together in harmony. If you're using the Shortcode Format for PayPal® Buttons,
2346
  * you won't even see these, because they're added internally by the Shortcode processor.
2347
  *
2348
- * The `ON1/OS1` values, are used by s2Member to identify a Customer's IP Address through IPN communications with PayPal®.
2349
  *
2350
  * Anyway, these five API Constants are just documented here for clarity;
2351
  * you probably won't use any of these directly; the Button Generator pops them in.
@@ -2370,7 +2370,7 @@ if (!class_exists ("c_ws_plugin__s2member_constants"))
2370
  *
2371
  * @see s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1
2372
  *
2373
- * @see `Dashboard -› s2Member -› PayPal® Buttons`
2374
  */
2375
  if (!defined ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1"))
2376
  define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1", ($c[] = (string)$_SERVER["REMOTE_ADDR"]));
31
  * Defines several API Constants for s2Member.
32
  *
33
  * These are also duplicated into the JavaScript API for s2Member.
34
+ * Except for a few that would pose a security issue. Such as the PayPal API Credentials;
35
  * those are NOT included in the JavaScript API.
36
  *
37
  * @package s2Member\API_Constants
323
  define ("S2MEMBER_CURRENT_USER_SUBSCR_ID", ($c[] = (($user) ? (string)$subscr_id : "")));
324
  /**
325
  * The current User's Paid Subscription ID (when applicable);
326
+ * otherwise, this will contain their WordPress User ID.
327
  *
328
  * An empty string if NOT logged-in.
329
  *
908
  if (!defined ("S2MEMBER_CURRENT_USER_REGISTRATION_IP"))
909
  define ("S2MEMBER_CURRENT_USER_REGISTRATION_IP", ($c[] = (($user) ? (string)$registration_ip : "")));
910
  /**
911
+ * The current User's WordPress User ID.
912
  *
913
  * This will be equal to `0` if NOT logged-in.
914
  *
1510
  /**
1511
  * The URL, which logs the current User out of their account.
1512
  *
1513
+ * This is the value provided by WordPress. It's the same as using ``wp_logout_url()``.
1514
  *
1515
  * ———— Quick PHP Code Sample ————
1516
  * ```
1550
  /**
1551
  * The URL, where a User can log into their account.
1552
  *
1553
+ * This is the value provided by WordPress. It's the same as using ``wp_login_url()``.
1554
  *
1555
  * ———— Quick PHP Code Sample ————
1556
  * ```
1833
  if (!defined ("S2MEMBER_REG_EMAIL_FROM_EMAIL"))
1834
  define ("S2MEMBER_REG_EMAIL_FROM_EMAIL", ($c[] = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"]));
1835
  /**
1836
+ * Full URL to PayPal IPN handler, provided by s2Member.
1837
  *
1838
  * ———— Quick PHP Code Sample ————
1839
  * ```
1856
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_RETURN_URL
1857
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_PDT_IDENTITY_TOKEN
1858
  *
1859
+ * @see `Dashboard -› s2Member -› PayPal Options -› IPN Integration`
1860
  */
1861
  if (!defined ("S2MEMBER_PAYPAL_NOTIFY_URL"))
1862
  define ("S2MEMBER_PAYPAL_NOTIFY_URL", ($c[] = (string)site_url ("/?s2member_paypal_notify=1")));
1863
  /**
1864
+ * Full URL to PayPal Auto-Return/PDT handler, provided by s2Member.
1865
  *
1866
  * ———— Quick PHP Code Sample ————
1867
  * ```
1884
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_NOTIFY_URL
1885
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_PDT_IDENTITY_TOKEN
1886
  *
1887
+ * @see `Dashboard -› s2Member -› PayPal Options -› Auto-Return/PDT Integration`
1888
  */
1889
  if (!defined ("S2MEMBER_PAYPAL_RETURN_URL"))
1890
  define ("S2MEMBER_PAYPAL_RETURN_URL", ($c[] = (string)site_url ("/?s2member_paypal_return=1")));
1891
  /**
1892
+ * PayPal Business Email Address; as configured by the site owner.
1893
  *
1894
  * ———— Quick PHP Code Sample ————
1895
  * ```
1913
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_PASSWORD
1914
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_SIGNATURE
1915
  *
1916
+ * @see `Dashboard -› s2Member -› PayPal Options -› Account Details`
1917
  */
1918
  if (!defined ("S2MEMBER_PAYPAL_BUSINESS"))
1919
  define ("S2MEMBER_PAYPAL_BUSINESS", ($c[] = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"]));
1920
  /**
1921
+ * PayPal endpoint domain (changes when Sandbox Mode is enabled).
1922
  *
1923
  * o In Sandbox Mode, this is: `www.sandbox.paypal.com`.
1924
  * o In Production Mode, this is: `www.paypal.com`.
1943
  *
1944
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_ENDPOINT
1945
  *
1946
+ * @see `Dashboard -› s2Member -› PayPal Options -› Account Details`
1947
  */
1948
  if (!defined ("S2MEMBER_PAYPAL_ENDPOINT"))
1949
  define ("S2MEMBER_PAYPAL_ENDPOINT", ($c[] = (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")));
1950
  /**
1951
+ * PayPal API endpoint domain (changes when Sandbox Mode is enabled).
1952
  *
1953
  * o In Sandbox Mode, this is: `api-3t.sandbox.paypal.com`.
1954
  * o In Production Mode, this is: `api-3t.paypal.com`.
1973
  *
1974
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_ENDPOINT
1975
  *
1976
+ * @see `Dashboard -› s2Member -› PayPal Options -› Account Details`
1977
  */
1978
  if (!defined ("S2MEMBER_PAYPAL_API_ENDPOINT"))
1979
  define ("S2MEMBER_PAYPAL_API_ENDPOINT", ($c[] = (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "api-3t.sandbox.paypal.com" : "api-3t.paypal.com")));
1980
  /**
1981
+ * PayPal API Username; as configured by the site owner.
1982
  *
1983
  * ———— Quick PHP Code Sample ————
1984
  * ```
2001
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_PASSWORD
2002
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_SIGNATURE
2003
  *
2004
+ * @see `Dashboard -› s2Member -› PayPal Options -› Account Details`
2005
  */
2006
  if (!defined ("S2MEMBER_PAYPAL_API_USERNAME"))
2007
  define ("S2MEMBER_PAYPAL_API_USERNAME", ($c[] = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_username"]));
2008
  /**
2009
+ * PayPal API Password; as configured by the site owner.
2010
  *
2011
  * ———— Quick PHP Code Sample ————
2012
  * ```
2029
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_USERNAME
2030
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_SIGNATURE
2031
  *
2032
+ * @see `Dashboard -› s2Member -› PayPal Options -› Account Details`
2033
  */
2034
  if (!defined ("S2MEMBER_PAYPAL_API_PASSWORD"))
2035
  define ("S2MEMBER_PAYPAL_API_PASSWORD", ($c[] = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_password"]));
2036
  /**
2037
+ * PayPal API Signature; as configured by the site owner.
2038
  *
2039
  * ———— Quick PHP Code Sample ————
2040
  * ```
2057
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_USERNAME
2058
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_API_PASSWORD
2059
  *
2060
+ * @see `Dashboard -› s2Member -› PayPal Options -› Account Details`
2061
  */
2062
  if (!defined ("S2MEMBER_PAYPAL_API_SIGNATURE"))
2063
  define ("S2MEMBER_PAYPAL_API_SIGNATURE", ($c[] = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_signature"]));
2064
  /**
2065
+ * PayPal PDT Identity Token; as configured by the site owner.
2066
  *
2067
  * ———— Quick PHP Code Sample ————
2068
  * ```
2084
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_RETURN_URL
2085
  * @see s2Member\API_Constants\S2MEMBER_PAYPAL_NOTIFY_URL
2086
  *
2087
+ * @see `Dashboard -› s2Member -› PayPal Options -› Auto-Return/PDT Integration`
2088
  */
2089
  if (!defined ("S2MEMBER_PAYPAL_PDT_IDENTITY_TOKEN"))
2090
  define ("S2MEMBER_PAYPAL_PDT_IDENTITY_TOKEN", ($c[] = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_identity_token"]));
2091
  /**
2092
+ * PayPal value for Payment Buttons with input name: `invoice`.
2093
  *
2094
+ * This can be used to auto-fill the `invoice` value in PayPal Button Codes, with a unique Code~IP combination.
2095
  * However, in cases where multiple Buttons are displayed on the same page, the alternative {@link s2Member\API_Functions\s2member_value_for_pp_inv()} function should be used instead.
2096
  *
2097
  * Note. This API Constant is excluded from the ``$c[]`` hash calculation used in the generation of {@link s2Member\API_Constants\WS_PLUGIN__S2MEMBER_API_CONSTANTS_MD5}.
2106
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1}
2107
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1}
2108
  *
2109
+ * They are used by the PayPal Button Generator for s2Member.
2110
  *
2111
+ * The `INV` value can be used to auto-fill the `invoice` for PayPal Button Codes, with a unique Code~IP combination.
2112
  * However, in cases where multiple Buttons are displayed on the same page, the alternative {@link s2Member\API_Functions\s2member_value_for_pp_inv()} function should be used instead.
2113
  *
2114
  * The `ON0/OS0` values, are how s2Member identifies an existing Member *(and/or a Free Subscriber)*, who is already logged-in
2115
+ * when they click a PayPal Modification Button that was generated for you by s2Member's Button Generator.
2116
  *
2117
  * Instead of forcing a Member *(and/or a Free Subscriber)* to re-register for a new account,
2118
  * s2Member can identify their existing account, and update it; according to the modified terms in your Button Code.
2119
+ * These three Button Code parameters: `on0`, `os0`, `modify`, work together in harmony. If you're using the Shortcode Format for PayPal Buttons,
2120
  * you won't even see these, because they're added internally by the Shortcode processor.
2121
  *
2122
+ * The `ON1/OS1` values, are used by s2Member to identify a Customer's IP Address through IPN communications with PayPal.
2123
  *
2124
  * Anyway, these five API Constants are just documented here for clarity;
2125
  * you probably won't use any of these directly; the Button Generator pops them in.
2144
  *
2145
  * @see s2Member\API_Functions\s2member_value_for_pp_inv()
2146
  *
2147
+ * @see `Dashboard -› s2Member -› PayPal Buttons`
2148
  */
2149
  if (!defined ("S2MEMBER_VALUE_FOR_PP_INV"))
2150
  define ("S2MEMBER_VALUE_FOR_PP_INV", uniqid () . "~" . S2MEMBER_CURRENT_USER_IP);
2151
  /**
2152
+ * PayPal value for Payment Buttons with input name: `on0`.
2153
  *
2154
+ * Used in PayPal Modification Buttons *(i.e. upgrades/downgrades)*.
2155
  *
2156
+ * This auto-fills the `on0` value in PayPal Button Codes. If a Button Code is presented to a logged-in Member,
2157
  * this will auto-fill the value for the `on0` input variable, with the string: "Referencing Customer ID".
2158
  * Otherwise, it will be set to a default value of: "Originating Domain".
2159
  *
2164
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1}
2165
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1}
2166
  *
2167
+ * They are used by the PayPal Button Generator for s2Member.
2168
  *
2169
+ * The `INV` value can be used to auto-fill the `invoice` for PayPal Button Codes, with a unique Code~IP combination.
2170
  * However, in cases where multiple Buttons are displayed on the same page, the alternative {@link s2Member\API_Functions\s2member_value_for_pp_inv()} function should be used instead.
2171
  *
2172
  * The `ON0/OS0` values, are how s2Member identifies an existing Member *(and/or a Free Subscriber)*, who is already logged-in
2173
+ * when they click a PayPal Modification Button that was generated for you by s2Member's Button Generator.
2174
  *
2175
  * Instead of forcing a Member *(and/or a Free Subscriber)* to re-register for a new account,
2176
  * s2Member can identify their existing account, and update it; according to the modified terms in your Button Code.
2177
+ * These three Button Code parameters: `on0`, `os0`, `modify`, work together in harmony. If you're using the Shortcode Format for PayPal Buttons,
2178
  * you won't even see these, because they're added internally by the Shortcode processor.
2179
  *
2180
+ * The `ON1/OS1` values, are used by s2Member to identify a Customer's IP Address through IPN communications with PayPal.
2181
  *
2182
  * Anyway, these five API Constants are just documented here for clarity;
2183
  * you probably won't use any of these directly; the Button Generator pops them in.
2202
  *
2203
  * @see s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS0
2204
  *
2205
+ * @see `Dashboard -› s2Member -› PayPal Buttons`
2206
  */
2207
  if (!defined ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0"))
2208
  define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0", ($c[] = ((S2MEMBER_CURRENT_USER_SUBSCR_OR_WP_ID) ? "Referencing Customer ID" : "Originating Domain")));
2209
  /**
2210
+ * PayPal value for Payment Buttons with input name: `os0`.
2211
  *
2212
+ * Used in PayPal Modification Buttons *(i.e. upgrades/downgrades)*.
2213
  *
2214
+ * This auto-fills the `os0` value in PayPal Button Codes. If a Button Code is presented to a logged-in Member,
2215
  * this will auto-fill the value for the `os0` input variable, with the value of {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_SUBSCR_OR_WP_ID}.
2216
  * Otherwise, it will be set to a default value of ``$_SERVER["HTTP_HOST"]`` *(the originating domain name)*.
2217
  *
2222
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1}
2223
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1}
2224
  *
2225
+ * They are used by the PayPal Button Generator for s2Member.
2226
  *
2227
+ * The `INV` value can be used to auto-fill the `invoice` for PayPal Button Codes, with a unique Code~IP combination.
2228
  * However, in cases where multiple Buttons are displayed on the same page, the alternative {@link s2Member\API_Functions\s2member_value_for_pp_inv()} function should be used instead.
2229
  *
2230
  * The `ON0/OS0` values, are how s2Member identifies an existing Member *(and/or a Free Subscriber)*, who is already logged-in
2231
+ * when they click a PayPal Modification Button that was generated for you by s2Member's Button Generator.
2232
  *
2233
  * Instead of forcing a Member *(and/or a Free Subscriber)* to re-register for a new account,
2234
  * s2Member can identify their existing account, and update it; according to the modified terms in your Button Code.
2235
+ * These three Button Code parameters: `on0`, `os0`, `modify`, work together in harmony. If you're using the Shortcode Format for PayPal Buttons,
2236
  * you won't even see these, because they're added internally by the Shortcode processor.
2237
  *
2238
+ * The `ON1/OS1` values, are used by s2Member to identify a Customer's IP Address through IPN communications with PayPal.
2239
  *
2240
  * Anyway, these five API Constants are just documented here for clarity;
2241
  * you probably won't use any of these directly; the Button Generator pops them in.
2260
  *
2261
  * @see s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0
2262
  *
2263
+ * @see `Dashboard -› s2Member -› PayPal Buttons`
2264
  */
2265
  if (!defined ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS0"))
2266
  define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS0", ($c[] = ((S2MEMBER_CURRENT_USER_SUBSCR_OR_WP_ID) ? S2MEMBER_CURRENT_USER_SUBSCR_OR_WP_ID : (string)$_SERVER["HTTP_HOST"])));
2267
  /**
2268
+ * PayPal value for Payment Buttons with input name: `on1`.
2269
  *
2270
+ * This auto-fills the `on1` value in PayPal Button Codes.
2271
  * This always contains the string: "Customer IP Address".
2272
  *
2273
  * These five API Constants are special.
2277
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1}
2278
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1}
2279
  *
2280
+ * They are used by the PayPal Button Generator for s2Member.
2281
  *
2282
+ * The `INV` value can be used to auto-fill the `invoice` for PayPal Button Codes, with a unique Code~IP combination.
2283
  * However, in cases where multiple Buttons are displayed on the same page, the alternative {@link s2Member\API_Functions\s2member_value_for_pp_inv()} function should be used instead.
2284
  *
2285
  * The `ON0/OS0` values, are how s2Member identifies an existing Member *(and/or a Free Subscriber)*, who is already logged-in
2286
+ * when they click a PayPal Modification Button that was generated for you by s2Member's Button Generator.
2287
  *
2288
  * Instead of forcing a Member *(and/or a Free Subscriber)* to re-register for a new account,
2289
  * s2Member can identify their existing account, and update it; according to the modified terms in your Button Code.
2290
+ * These three Button Code parameters: `on0`, `os0`, `modify`, work together in harmony. If you're using the Shortcode Format for PayPal Buttons,
2291
  * you won't even see these, because they're added internally by the Shortcode processor.
2292
  *
2293
+ * The `ON1/OS1` values, are used by s2Member to identify a Customer's IP Address through IPN communications with PayPal.
2294
  *
2295
  * Anyway, these five API Constants are just documented here for clarity;
2296
  * you probably won't use any of these directly; the Button Generator pops them in.
2315
  *
2316
  * @see s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1
2317
  *
2318
+ * @see `Dashboard -› s2Member -› PayPal Buttons`
2319
  */
2320
  if (!defined ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1"))
2321
  define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1", ($c[] = "Customer IP Address" /* Via $_SERVER["REMOTE_ADDR"] below. */));
2322
  /**
2323
+ * PayPal value for Payment Buttons with input name: `os1`.
2324
  *
2325
+ * This auto-fills the `os1` value in PayPal Button Codes,
2326
  * with the Customer's IP Address, via ``$_SERVER["REMOTE_ADDR"]``.
2327
  *
2328
  * These five API Constants are special.
2332
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1}
2333
  * o {@link s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1}
2334
  *
2335
+ * They are used by the PayPal Button Generator for s2Member.
2336
  *
2337
+ * The `INV` value can be used to auto-fill the `invoice` for PayPal Button Codes, with a unique Code~IP combination.
2338
  * However, in cases where multiple Buttons are displayed on the same page, the alternative {@link s2Member\API_Functions\s2member_value_for_pp_inv()} function should be used instead.
2339
  *
2340
  * The `ON0/OS0` values, are how s2Member identifies an existing Member *(and/or a Free Subscriber)*, who is already logged-in
2341
+ * when they click a PayPal Modification Button that was generated for you by s2Member's Button Generator.
2342
  *
2343
  * Instead of forcing a Member *(and/or a Free Subscriber)* to re-register for a new account,
2344
  * s2Member can identify their existing account, and update it; according to the modified terms in your Button Code.
2345
+ * These three Button Code parameters: `on0`, `os0`, `modify`, work together in harmony. If you're using the Shortcode Format for PayPal Buttons,
2346
  * you won't even see these, because they're added internally by the Shortcode processor.
2347
  *
2348
+ * The `ON1/OS1` values, are used by s2Member to identify a Customer's IP Address through IPN communications with PayPal.
2349
  *
2350
  * Anyway, these five API Constants are just documented here for clarity;
2351
  * you probably won't use any of these directly; the Button Generator pops them in.
2370
  *
2371
  * @see s2Member\API_Constants\S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON1
2372
  *
2373
+ * @see `Dashboard -› s2Member -› PayPal Buttons`
2374
  */
2375
  if (!defined ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1"))
2376
  define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS1", ($c[] = (string)$_SERVER["REMOTE_ADDR"]));
includes/classes/custom-reg-fields.inc.php CHANGED
@@ -160,7 +160,7 @@ if(!class_exists("c_ws_plugin__s2member_custom_reg_fields"))
160
  {
161
  $gen = '<input type="checkbox" value="1"';
162
  $gen .= (((string)$_value) ? ' checked="checked"' : '');
163
- $gen .= $common.' /><label for="'.esc_attr($_id_prefix.$field_id_class).'" style="display:inline !important; margin:0 !important;">'.$field["label"].'</label>';
164
  }
165
  }
166
  else if($field["type"] === "pre_checkbox" && !empty($field["label"]))
@@ -172,7 +172,7 @@ if(!class_exists("c_ws_plugin__s2member_custom_reg_fields"))
172
  {
173
  $gen = '<input type="checkbox" value="1"';
174
  $gen .= ((!$_submission || (string)$_value) ? ' checked="checked"' : '');
175
- $gen .= $common.' /><label for="'.esc_attr($_id_prefix.$field_id_class).'" style="display:inline !important; margin:0 !important;">'.$field["label"].'</label>';
176
  }
177
  }
178
  else if($field["type"] === "checkboxes" && !empty($field["options"]))
@@ -203,7 +203,7 @@ if(!class_exists("c_ws_plugin__s2member_custom_reg_fields"))
203
  $gen .= ($i > 0) ? $sep : ''; // Separators can be filtered above.
204
  $gen .= '<input type="checkbox" value="'.esc_attr($option_value).'"';
205
  $gen .= ((($option_default && !$_submission) || in_array($option_value, (array)$_value)) ? ' checked="checked"' : '');
206
- $gen .= $common_i.' /><label for="'.esc_attr($_id_prefix.$field_id_class."-".$i).'" class="'.esc_attr($opl).'" style="display:inline !important; margin:0 !important;">'.$option_label.'</label>';
207
  }
208
  }
209
  }
@@ -235,7 +235,7 @@ if(!class_exists("c_ws_plugin__s2member_custom_reg_fields"))
235
  $gen .= ($i > 0) ? $sep : ''; // Separators can be filtered above.
236
  $gen .= '<input type="radio" value="'.esc_attr($option_value).'"';
237
  $gen .= ((($option_default && !$_submission) || $option_value === (string)$_value) ? ' checked="checked"' : '');
238
- $gen .= $common_i.' /><label for="'.esc_attr($_id_prefix.$field_id_class."-".$i).'" class="'.esc_attr($opl).'" style="display:inline !important; margin:0 !important;">'.$option_label.'</label>';
239
  }
240
  }
241
  }
160
  {
161
  $gen = '<input type="checkbox" value="1"';
162
  $gen .= (((string)$_value) ? ' checked="checked"' : '');
163
+ $gen .= $common.' /> <label for="'.esc_attr($_id_prefix.$field_id_class).'" style="display:inline !important; margin:0 !important;">'.$field["label"].'</label>';
164
  }
165
  }
166
  else if($field["type"] === "pre_checkbox" && !empty($field["label"]))
172
  {
173
  $gen = '<input type="checkbox" value="1"';
174
  $gen .= ((!$_submission || (string)$_value) ? ' checked="checked"' : '');
175
+ $gen .= $common.' /> <label for="'.esc_attr($_id_prefix.$field_id_class).'" style="display:inline !important; margin:0 !important;">'.$field["label"].'</label>';
176
  }
177
  }
178
  else if($field["type"] === "checkboxes" && !empty($field["options"]))
203
  $gen .= ($i > 0) ? $sep : ''; // Separators can be filtered above.
204
  $gen .= '<input type="checkbox" value="'.esc_attr($option_value).'"';
205
  $gen .= ((($option_default && !$_submission) || in_array($option_value, (array)$_value)) ? ' checked="checked"' : '');
206
+ $gen .= $common_i.' /> <label for="'.esc_attr($_id_prefix.$field_id_class."-".$i).'" class="'.esc_attr($opl).'" style="display:inline !important; margin:0 !important;">'.$option_label.'</label>';
207
  }
208
  }
209
  }
235
  $gen .= ($i > 0) ? $sep : ''; // Separators can be filtered above.
236
  $gen .= '<input type="radio" value="'.esc_attr($option_value).'"';
237
  $gen .= ((($option_default && !$_submission) || $option_value === (string)$_value) ? ' checked="checked"' : '');
238
+ $gen .= $common_i.' /> <label for="'.esc_attr($_id_prefix.$field_id_class."-".$i).'" class="'.esc_attr($opl).'" style="display:inline !important; margin:0 !important;">'.$option_label.'</label>';
239
  }
240
  }
241
  }
includes/classes/email-configs.inc.php CHANGED
@@ -121,7 +121,7 @@ if (!class_exists ("c_ws_plugin__s2member_email_configs"))
121
  remove_filter ("wp_mail_from", "c_ws_plugin__s2member_email_configs::_email_config_email");
122
  remove_filter ("wp_mail_from_name", "c_ws_plugin__s2member_email_configs::_email_config_name");
123
 
124
- if /* If ``$all`` is true, remove ALL attached WordPress® Filters. */ ($all)
125
  remove_all_filters ("wp_mail_from") . remove_all_filters ("wp_mail_from_name");
126
 
127
  do_action ("ws_plugin__s2member_after_email_config_release", get_defined_vars ());
@@ -129,7 +129,7 @@ if (!class_exists ("c_ws_plugin__s2member_email_configs"))
129
  return /* Return for uniformity. */;
130
  }
131
  /**
132
- * Converts primitive Role names in emails sent by WordPress®.
133
  *
134
  * Only necessary with this particular email: `wpmu_signup_user_notification_email`.
135
  *
@@ -168,7 +168,7 @@ if (!class_exists ("c_ws_plugin__s2member_email_configs"))
168
  if (isset ($array["to"]) && !empty ($array["to"])) // Filter list of recipients?
169
  // Reduces `"Name" <email>`, to just an email address *(for best cross-platform compatibility across various MTAs)*.
170
  // Also works around bug in PHP versions prior to fix in 5.2.11. See bug report: <https://bugs.php.net/bug.php?id=28038>.
171
- // Also supplements WordPress®. WordPress® currently does NOT support semicolon `;` delimitation, s2Member does.
172
  $array["to"] = implode (",", c_ws_plugin__s2member_utils_strings::parse_emails ($array["to"]));
173
 
174
  return apply_filters ("ws_plugin__s2member_after_email_filter", $array, get_defined_vars ());
@@ -179,7 +179,7 @@ if (!class_exists ("c_ws_plugin__s2member_email_configs"))
179
  * @package s2Member\Email_Configs
180
  * @since 110707
181
  *
182
- * @param str|int $user_id A numeric WordPress® User ID.
183
  * @param str $user_pass Optional. A plain text version of the User's password.
184
  * If omitted, a new password will be generated automatically.
185
  * @param array $notify An array of directives. Must be non-empty, with at least one of these values `user,admin`.
@@ -209,7 +209,7 @@ if (!class_exists ("c_ws_plugin__s2member_email_configs"))
209
  * @package s2Member\Email_Configs
210
  * @since 110707
211
  *
212
- * @param str|int $user_id A numeric WordPress® User ID.
213
  * @param str $user_pass Optional. A plain text version of the User's password.
214
  * If omitted, only the administrative notification will be sent.
215
  * @param array $notify An array of directives. Must be non-empty, with at least one of these values `user,admin`.
121
  remove_filter ("wp_mail_from", "c_ws_plugin__s2member_email_configs::_email_config_email");
122
  remove_filter ("wp_mail_from_name", "c_ws_plugin__s2member_email_configs::_email_config_name");
123
 
124
+ if /* If ``$all`` is true, remove ALL attached WordPress Filters. */ ($all)
125
  remove_all_filters ("wp_mail_from") . remove_all_filters ("wp_mail_from_name");
126
 
127
  do_action ("ws_plugin__s2member_after_email_config_release", get_defined_vars ());
129
  return /* Return for uniformity. */;
130
  }
131
  /**
132
+ * Converts primitive Role names in emails sent by WordPress.
133
  *
134
  * Only necessary with this particular email: `wpmu_signup_user_notification_email`.
135
  *
168
  if (isset ($array["to"]) && !empty ($array["to"])) // Filter list of recipients?
169
  // Reduces `"Name" <email>`, to just an email address *(for best cross-platform compatibility across various MTAs)*.
170
  // Also works around bug in PHP versions prior to fix in 5.2.11. See bug report: <https://bugs.php.net/bug.php?id=28038>.
171
+ // Also supplements WordPress. WordPress currently does NOT support semicolon `;` delimitation, s2Member does.
172
  $array["to"] = implode (",", c_ws_plugin__s2member_utils_strings::parse_emails ($array["to"]));
173
 
174
  return apply_filters ("ws_plugin__s2member_after_email_filter", $array, get_defined_vars ());
179
  * @package s2Member\Email_Configs
180
  * @since 110707
181
  *
182
+ * @param str|int $user_id A numeric WordPress User ID.
183
  * @param str $user_pass Optional. A plain text version of the User's password.
184
  * If omitted, a new password will be generated automatically.
185
  * @param array $notify An array of directives. Must be non-empty, with at least one of these values `user,admin`.
209
  * @package s2Member\Email_Configs
210
  * @since 110707
211
  *
212
+ * @param str|int $user_id A numeric WordPress User ID.
213
  * @param str $user_pass Optional. A plain text version of the User's password.
214
  * If omitted, only the administrative notification will be sent.
215
  * @param array $notify An array of directives. Must be non-empty, with at least one of these values `user,admin`.
includes/classes/files-in.inc.php CHANGED
@@ -516,7 +516,7 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
516
  *
517
  * @param array $config Required. This is an array of configuration options associated with permissions being checked against the current User/Member; and also the actual URL generated by this routine.
518
  * Possible ``$config`` array elements: `file_download` *(required)*, `file_download_key`, `file_stream`, `file_inline`, `file_storage`, `file_remote`, `file_ssl`, `file_rewrite`, `file_rewrite_base`, `skip_confirmation`, `url_to_storage_source`, `count_against_user`, `check_user`.
519
- * @param bool $get_streamer_array Optional. Defaults to `false`. If `true`, this function will return an array with the following elements: `streamer`, `file`, `url`. For further details, please review this section in your Dashboard: `s2Member -› Download Options -› JW Player® & RTMP Protocol Examples`.
520
  * @return str A File Download URL string on success; or an array on success, with elements `streamer`, `file`, `url` when/if ``$get_streamer_array`` is true; else false on any type of failure.
521
  *
522
  * @see s2Member\API_Functions\s2member_file_download_url()
@@ -628,13 +628,13 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
628
  return apply_filters("ws_plugin__s2member_check_file_download_key", ((isset($valid) && $valid) ? true : false), get_defined_vars());
629
  }
630
  /**
631
- * Creates an Amazon® S3 HMAC-SHA1 signature.
632
  *
633
  * @package s2Member\Files
634
  * @since 110524RC
635
  *
636
  * @param str $string Input string/data, to be signed by this routine.
637
- * @return str An HMAC-SHA1 signature for Amazon® S3.
638
  */
639
  public static function amazon_s3_sign($string = FALSE)
640
  {
@@ -643,7 +643,7 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
643
  return c_ws_plugin__s2member_utils_strings::hmac_sha1_sign((string)$string, $s3c["secret_key"]);
644
  }
645
  /**
646
- * Creates an Amazon® S3 HMAC-SHA1 signature URL.
647
  *
648
  * @package s2Member\Files
649
  * @since 110926
@@ -654,7 +654,7 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
654
  * @param bool $ssl Is this resource file to be served via SSL, or no?
655
  * @param str $basename The absolute basename of the resource file.
656
  * @param str $mimetype The MIME content-type of the resource file.
657
- * @return str An HMAC-SHA1 signature URL for Amazon® S3.
658
  */
659
  public static function amazon_s3_url($file = FALSE, $stream = FALSE, $inline = FALSE, $ssl = FALSE, $basename = FALSE, $mimetype = FALSE)
660
  {
@@ -677,7 +677,7 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
677
  return add_query_arg(c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep (urlencode_deep(array("AWSAccessKeyId" => $s3c["access_key"], "Expires" => $s3c["expires"], "Signature" => $s3_signature))), $s3_url);
678
  }
679
  /**
680
- * Auto-configures an Amazon® S3 Bucket's ACLs.
681
  *
682
  * @package s2Member\Files
683
  * @since 110926
@@ -693,7 +693,7 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
693
 
694
  $cfc["distros_s3_access_id"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distros_s3_access_id"];
695
 
696
- if /* Must have Amazon® S3 Bucket/Keys. */($s3c["bucket"] && $s3c["access_key"] && $s3c["secret_key"])
697
  {
698
  $s3_date = gmdate("D, d M Y H:i:s")." GMT";
699
  $s3_location = ((strtolower($s3c["bucket"]) !== $s3c["bucket"])) ? "/".$s3c["bucket"]."/?acl" : "/?acl";
@@ -726,50 +726,50 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
726
  $s3_args = array("method" => "PUT", "redirection" => 0, "body" => $s3_policy_xml, "headers" => array("Host" => $s3_domain, "Content-Type" => "text/xml", "Date" => $s3_date, "X-Amz-Acl" => "public-read", "Authorization" => "AWS ".$s3c["access_key"].":".$s3_signature));
727
 
728
  if(($s3_response = c_ws_plugin__s2member_utils_urls::remote("https://".$s3_domain.$s3_location, false, array_merge($s3_args, array("timeout" => 20)), "array")) && $s3_response["code"] === 200)
729
- return /* Successfully configured Amazon® S3 Bucket ACLs and Policy. */ array("success" => true, "code" => null, "message" => null);
730
 
731
  else if(isset($s3_response["code"], $s3_response["message"]))
732
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® S3 API call. Feel free to exclude `%s` if you like. */
733
- return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to update existing Amazon® S3 Cross-Domain Policy. %s", "s2member-admin", "s2member"), $s3_response["message"]));
734
 
735
  else // Else, we use a default error code and message.
736
- return array("success" => false, "code" => -94, "message" => _x("Unable to update existing Amazon® S3 Cross-Domain Policy. Connection failed.", "s2member-admin", "s2member"));
737
  }
738
  else if(isset($s3_response["code"], $s3_response["message"]))
739
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® S3 API call. Feel free to exclude `%s` if you like. */
740
- return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to update existing Amazon® S3 Bucket Policy. %s", "s2member-admin", "s2member"), $s3_response["message"]));
741
 
742
  else // Else, we use a default error code and message.
743
- return array("success" => false, "code" => -95, "message" => _x("Unable to update existing Amazon® S3 Bucket Policy. Connection failed.", "s2member-admin", "s2member"));
744
  }
745
  else if(isset($s3_response["code"], $s3_response["message"]))
746
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® S3 API call. Feel free to exclude `%s` if you like. */
747
- return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to update existing Amazon® S3 Bucket ACLs. %s", "s2member-admin", "s2member"), $s3_response["message"]));
748
 
749
  else // Else, we use a default error code and message.
750
- return array("success" => false, "code" => -96, "message" => _x("Unable to update existing Amazon® S3 Bucket ACLs. Connection failed.", "s2member-admin", "s2member"));
751
  }
752
  else // Else, we use a default error code and message.
753
- return array("success" => false, "code" => -97, "message" => _x("Unable to acquire/read existing Amazon® S3 Bucket ACLs. Unexpected response.", "s2member-admin", "s2member"));
754
  }
755
  else if(isset($s3_response["code"], $s3_response["message"]))
756
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® S3 API call. Feel free to exclude `%s` if you like. */
757
- return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon® S3 Bucket ACLs. %s", "s2member-admin", "s2member"), $s3_response["message"]));
758
 
759
  else // Else, we use a default error code and message.
760
- return array("success" => false, "code" => -98, "message" => _x("Unable to acquire existing Amazon® S3 Bucket ACLs. Connection failed.", "s2member-admin", "s2member"));
761
  }
762
  else // Else, we use a default error code and message.
763
- return array("success" => false, "code" => -99, "message" => _x("Unable to auto-configure existing Amazon® S3 Bucket ACLs. Incomplete Amazon® S3 configuration options. Missing one of: Amazon® S3 Bucket, Access Key, or Secret Key.", "s2member-admin", "s2member"));
764
  }
765
  /**
766
- * Creates an Amazon® CloudFront HMAC-SHA1 signature.
767
  *
768
  * @package s2Member\Files
769
  * @since 110926
770
  *
771
  * @param str $string Input string/data, to be signed by this routine.
772
- * @return str An HMAC-SHA1 signature for Amazon® CloudFront.
773
  */
774
  public static function amazon_cf_sign($string = FALSE)
775
  {
@@ -778,13 +778,13 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
778
  return c_ws_plugin__s2member_utils_strings::hmac_sha1_sign((string)$string, ($cfc["secret_key"] = $s3c["secret_key"]));
779
  }
780
  /**
781
- * Creates an Amazon® CloudFront RSA-SHA1 signature.
782
  *
783
  * @package s2Member\Files
784
  * @since 110926
785
  *
786
  * @param str $string Input string/data, to be signed by this routine.
787
- * @return str|bool An RSA-SHA1 signature for Amazon® CloudFront, else false on failure.
788
  */
789
  public static function amazon_cf_rsa_sign($string = FALSE)
790
  {
@@ -793,7 +793,7 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
793
  return c_ws_plugin__s2member_utils_strings::rsa_sha1_sign((string)$string, $cfc["private_key"]);
794
  }
795
  /**
796
- * Creates an Amazon® CloudFront RSA-SHA1 signature URL.
797
  *
798
  * @package s2Member\Files
799
  * @since 110926
@@ -804,7 +804,7 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
804
  * @param bool $ssl Is this resource file to be served via SSL, or no?
805
  * @param str $basename The absolute basename of the resource file.
806
  * @param str $mimetype The MIME content-type of the resource file.
807
- * @return str An RSA-SHA1 signature URL for Amazon® CloudFront.
808
  */
809
  public static function amazon_cf_url($file = FALSE, $stream = FALSE, $inline = FALSE, $ssl = FALSE, $basename = FALSE, $mimetype = FALSE)
810
  {
@@ -819,7 +819,7 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
819
  $cfc["expires"] = strtotime("+".apply_filters("ws_plugin__s2member_amazon_cf_file_expires_time", "24 hours", get_defined_vars()));
820
 
821
  $cf_extn = /* Parses the file extension out so we can scan it in some special scenarios. */ strtolower(substr($file, strrpos($file, ".") + 1));
822
- $cf_ip_res = /* Do NOT restrict access to a particular IP during `localhost` development. The IP may NOT be the same one Amazon® CloudFront sees. */ (c_ws_plugin__s2member_utils_conds::is_localhost()) ? false : true;
823
  $cf_stream_extn_resource_exclusions = array_unique((array)apply_filters("ws_plugin__s2member_amazon_cf_file_streaming_extension_resource_exclusions", array("mp3" /* MP3 files should NOT include an extension in their resource reference. */), get_defined_vars()));
824
  $cf_resource = ($stream) ? ((in_array($cf_extn, $cf_stream_extn_resource_exclusions)) ? substr($file, 0, strrpos($file, ".")) : $file) : "http".(($ssl) ? "s" : "")."://".(($cfc["distro_downloads_cname"]) ? $cfc["distro_downloads_cname"] : $cfc["distro_downloads_dname"])."/".$url_e_file;
825
  $cf_url = ($stream) ? "rtmp".(($ssl) ? "e" : "")."://".(($cfc["distro_streaming_cname"]) ? $cfc["distro_streaming_cname"] : $cfc["distro_streaming_dname"])."/cfx/st/".$file : "http".(($ssl) ? "s" : "")."://".(($cfc["distro_downloads_cname"]) ? $cfc["distro_downloads_cname"] : $cfc["distro_downloads_dname"])."/".$url_e_file;
@@ -832,7 +832,7 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
832
  return add_query_arg(c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode_deep(array("Policy" => $cf_base64_url_safe_policy, "Signature" => $cf_base64_url_safe_signature, "Key-Pair-Id" => $cfc["private_key_id"]))), $cf_url);
833
  }
834
  /**
835
- * Auto-configures Amazon® S3/CloudFront distros.
836
  *
837
  * @package s2Member\Files
838
  * @since 110926
@@ -850,9 +850,9 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
850
  $cfc["access_key"] = $s3c["access_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_access_key"];
851
  $cfc["secret_key"] = $s3c["secret_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"];
852
 
853
- if /* We MUST have an Amazon® S3 Bucket and Keys. */($s3c["bucket"] && $s3c["access_key"] && $s3c["secret_key"])
854
  {
855
- if /* We MUST have Amazon® CloudFront Keys in order to auto-configure. */($cfc["private_key"] && $cfc["private_key_id"])
856
  {
857
  if(!$cfc["distro_downloads_id"] || ($cfc["distro_downloads_id"] && ($cf_get_response = c_ws_plugin__s2member_files_in::amazon_cf_get_distro($cfc["distro_downloads_id"], "downloads")) && ($cf_get_response["success"] || $cf_get_response["code"] === 404)))
858
  {
@@ -860,14 +860,14 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
860
  $cf_distro_downloads_clear = /* Clear, ready for a new one. */ true;
861
 
862
  else if($cfc["distro_downloads_id"] && $cf_get_response && $cf_get_response["success"] && !$cf_get_response["deployed"])
863
- return array("success" => false, "code" => -86, "message" => _x("Unable to delete existing Amazon® CloudFront Downloads Distro. Still in a `pending` state. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon® CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon® CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
864
 
865
  else if($cfc["distro_downloads_id"] && $cf_get_response && $cf_get_response["success"] && $cf_get_response["deployed"] && ($cf_del_response = c_ws_plugin__s2member_files_in::amazon_cf_del_distro($cfc["distro_downloads_id"], $cf_get_response["etag"], $cf_get_response["xml"])) && $cf_del_response["success"])
866
  $cf_distro_downloads_clear = /* Clear, ready for a new one. */ true;
867
 
868
  else if(isset($cf_del_response["code"], $cf_del_response["message"]))
869
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
870
- return array("success" => false, "code" => $cf_del_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon® CloudFront Downloads Distro. %s", "s2member-admin", "s2member"), $cf_del_response["message"]));
871
 
872
  if /* Successfully cleared? Ready for a new one? */(isset($cf_distro_downloads_clear) && $cf_distro_downloads_clear)
873
  {
@@ -879,14 +879,14 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
879
  $cf_distro_streaming_clear = /* Clear, ready for a new one. */ true;
880
 
881
  else if($cfc["distro_streaming_id"] && $cf_get_response && $cf_get_response["success"] && !$cf_get_response["deployed"])
882
- return array("success" => false, "code" => -87, "message" => _x("Unable to delete existing Amazon® CloudFront Streaming Distro. Still in a `pending` state. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon® CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon® CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
883
 
884
  else if($cfc["distro_streaming_id"] && $cf_get_response && $cf_get_response["success"] && $cf_get_response["deployed"] && ($cf_del_response = c_ws_plugin__s2member_files_in::amazon_cf_del_distro($cfc["distro_streaming_id"], $cf_get_response["etag"], $cf_get_response["xml"])) && $cf_del_response["success"])
885
  $cf_distro_streaming_clear = /* Clear, ready for a new one. */ true;
886
 
887
  else if(isset($cf_del_response["code"], $cf_del_response["message"]))
888
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
889
- return array("success" => false, "code" => $cf_del_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon® CloudFront Streaming Distro. %s", "s2member-admin", "s2member"), $cf_del_response["message"]));
890
 
891
  if /* Successfully cleared? Ready for a new one? */(isset($cf_distro_streaming_clear) && $cf_distro_streaming_clear)
892
  {
@@ -901,8 +901,8 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
901
  $cf_distros_access_clear = /* Clear, ready for a new one. */ true;
902
 
903
  else if(isset($cf_del_response["code"], $cf_del_response["message"]))
904
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
905
- return array("success" => false, "code" => $cf_del_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon® CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_del_response["message"]));
906
 
907
  if /* Successfully cleared? Ready for a new one? */(isset($cf_distros_access_clear) && $cf_distros_access_clear)
908
  {
@@ -939,74 +939,74 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
939
  $cfc = array_merge($cfc, array("distros_auto_config_status" => "configured"));
940
  $cf_options = array("ws_plugin__s2member_amazon_cf_files_distros_auto_config_status" => "configured");
941
  c_ws_plugin__s2member_menu_pages::update_all_options( /* Now configured! */$cf_options, true, false, false, false, false);
942
- return /* Successfully configured Amazon® S3/CloudFront distros. */ array("success" => true, "code" => null, "message" => null);
943
  }
944
  if(isset($s3_response["code"], $s3_response["message"]))
945
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® S3 API call. Feel free to exclude `%s` if you like. */
946
- return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to update existing Amazon® S3 ACLs. %s", "s2member-admin", "s2member"), $s3_response["message"]));
947
 
948
  else // Else, we use a default error code and message.
949
- return array("success" => false, "code" => -88, "message" => _x("Unable to update existing Amazon® S3 ACLs. Connection failed.", "s2member-admin", "s2member"));
950
  }
951
  else if(isset($cf_response["code"], $cf_response["message"]))
952
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
953
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon® CloudFront Streaming Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
954
 
955
  else // Else, we use a default error code and message.
956
- return array("success" => false, "code" => -89, "message" => _x("Unable to create Amazon® CloudFront Streaming Distro. Connection failed.", "s2member-admin", "s2member"));
957
  }
958
  else if(isset($cf_response["code"], $cf_response["message"]))
959
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
960
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon® CloudFront Downloads Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
961
 
962
  else // Else, we use a default error code and message.
963
- return array("success" => false, "code" => -90, "message" => _x("Unable to create Amazon® CloudFront Downloads Distro. Connection failed.", "s2member-admin", "s2member"));
964
  }
965
  else if(isset($cf_response["code"], $cf_response["message"]))
966
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
967
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon® CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_response["message"]));
968
 
969
  else // Else, we use a default error code and message.
970
- return array("success" => false, "code" => -91, "message" => _x("Unable to create Amazon® CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
971
  }
972
  else // Else, we use a default error code and message.
973
- return array("success" => false, "code" => -92, "message" => _x("Unable to clear existing Amazon® CloudFront Origin Access Identity.", "s2member-admin", "s2member"));
974
  }
975
  else if(isset($cf_get_response["code"], $cf_get_response["message"]))
976
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
977
- return array("success" => false, "code" => $cf_get_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon® CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_get_response["message"]));
978
 
979
  else // Else, we use a default error code and message.
980
- return array("success" => false, "code" => -93, "message" => _x("Unable to acquire existing Amazon® CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
981
  }
982
  else // Else, we use a default error code and message.
983
- return array("success" => false, "code" => -94, "message" => _x("Unable to clear existing Amazon® CloudFront Streaming Distro.", "s2member-admin", "s2member"));
984
  }
985
  else if(isset($cf_get_response["code"], $cf_get_response["message"]))
986
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
987
- return array("success" => false, "code" => $cf_get_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon® CloudFront Streaming Distro. %s", "s2member-admin", "s2member"), $cf_get_response["message"]));
988
 
989
  else // Else, we use a default error code and message.
990
- return array("success" => false, "code" => -95, "message" => _x("Unable to acquire existing Amazon® CloudFront Streaming Distro. Connection failed.", "s2member-admin", "s2member"));
991
  }
992
  else // Else, we use a default error code and message.
993
- return array("success" => false, "code" => -96, "message" => _x("Unable to clear existing Amazon® CloudFront Downloads Distro.", "s2member-admin", "s2member"));
994
  }
995
  else if(isset($cf_get_response["code"], $cf_get_response["message"]))
996
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
997
- return array("success" => false, "code" => $cf_get_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon® CloudFront Downloads Distro. %s", "s2member-admin", "s2member"), $cf_get_response["message"]));
998
 
999
  else // Else, we use a default error code and message.
1000
- return array("success" => false, "code" => -97, "message" => _x("Unable to acquire existing Amazon® CloudFront Downloads Distro. Connection failed.", "s2member-admin", "s2member"));
1001
  }
1002
  else // Else, we use a default error code and message.
1003
- return array("success" => false, "code" => -98, "message" => _x("Unable to auto-configure Amazon® CloudFront Distros. Incomplete Amazon® CloudFront configuration options. Missing of one: Amazon® CloudFront Private Key-Pair-ID, or Private Key file contents.", "s2member-admin", "s2member"));
1004
  }
1005
  else // Else, we use a default error code and message.
1006
- return array("success" => false, "code" => -99, "message" => _x("Unable to auto-configure Amazon® S3/CloudFront Distros. Incomplete Amazon® S3 configuration options. Missing one of: Amazon® S3 Bucket, Access Key, or Secret Key. You must provide s2Member with an Amazon® S3 configuration before enabling CloudFront.", "s2member-admin", "s2member"));
1007
  }
1008
  /**
1009
- * Acquires an Amazon® S3/CloudFront Access Origin Identity.
1010
  *
1011
  * @package s2Member\Files
1012
  * @since 110926
@@ -1038,21 +1038,21 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
1038
  if($cf_response["code"] === 200 && !empty($cf_response["headers"]["etag"]) && !empty($cf_response["body"]))
1039
  return array("success" => true, "code" => null, "message" => null, "etag" => trim($cf_response["headers"]["etag"]), "xml" => trim($cf_response["body"]));
1040
 
1041
- else /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
1042
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Existing Amazon® CloudFront Origin Access Identity NOT found. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1043
  }
1044
  else if(isset($cf_response["code"], $cf_response["message"]))
1045
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
1046
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon® CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1047
 
1048
  else // Else, we use a default error code and message.
1049
- return array("success" => false, "code" => -98, "message" => _x("Unable to acquire existing Amazon® CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
1050
  }
1051
  else // Else, we use a default error code and message.
1052
- return array("success" => false, "code" => -99, "message" => _x("Unable to acquire existing Amazon® CloudFront Origin Access Identity. Invalid Access ID.", "s2member-admin", "s2member"));
1053
  }
1054
  /**
1055
- * Deletes an Amazon® S3/CloudFront Access Origin Identity.
1056
  *
1057
  * @package s2Member\Files
1058
  * @since 110926
@@ -1085,17 +1085,17 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
1085
  return /* Deleted successfully. */ array("success" => true, "code" => null, "message" => null);
1086
 
1087
  else if(isset($cf_response["code"], $cf_response["message"]))
1088
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
1089
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon® CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1090
 
1091
  else // Else, we use a default error code and message.
1092
- return array("success" => false, "code" => -98, "message" => _x("Unable to delete existing Amazon® CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
1093
  }
1094
  else // Else, we use a default error code and message.
1095
- return array("success" => false, "code" => -99, "message" => _x("Unable to delete existing Amazon® CloudFront Origin Access Identity. Invalid Access ID, ETag, or XML config.", "s2member-admin", "s2member"));
1096
  }
1097
  /**
1098
- * Creates an Amazon® S3/CloudFront Access Origin Identity for all Distros.
1099
  *
1100
  * @package s2Member\Files
1101
  * @since 110926
@@ -1127,17 +1127,17 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
1127
  return array("success" => true, "code" => null, "message" => null, "distros_access_id" => trim($cf_distros_access_id_tag[1]), "distros_s3_access_id" => trim($cf_distros_s3_access_id_tag[1]));
1128
 
1129
  else // Else, we use a default error code and message.
1130
- return array("success" => false, "code" => -98, "message" => _x("Unable to create/read Amazon® CloudFront Origin Access Identity. Unexpected response.", "s2member-admin", "s2member"));
1131
  }
1132
  else if(isset($cf_response["code"], $cf_response["message"]))
1133
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
1134
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon® CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1135
 
1136
  else // Else, we use a default error code and message.
1137
- return array("success" => false, "code" => -99, "message" => _x("Unable to create Amazon® CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
1138
  }
1139
  /**
1140
- * Acquires an Amazon® S3/CloudFront Distro.
1141
  *
1142
  * @package s2Member\Files
1143
  * @since 110926
@@ -1170,21 +1170,21 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
1170
  if($cf_response["code"] === 200 && !empty($cf_response["headers"]["etag"]) && !empty($cf_response["body"]))
1171
  return array("success" => true, "code" => null, "message" => null, "etag" => trim($cf_response["headers"]["etag"]), "xml" => trim($cf_response["body"]), "deployed" => ((stripos($cf_response["body"], "<Status>Deployed</Status>") !== false) ? true : false));
1172
 
1173
- else /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
1174
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Existing Amazon® CloudFront Distro NOT found. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1175
  }
1176
  else if(isset($cf_response["code"], $cf_response["message"]))
1177
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
1178
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon® CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1179
 
1180
  else // Else, we use a default error code and message.
1181
- return array("success" => false, "code" => -98, "message" => _x("Unable to acquire existing Amazon® CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1182
  }
1183
  else // Else, we use a default error code and message.
1184
- return array("success" => false, "code" => -99, "message" => _x("Unable to acquire existing Amazon® CloudFront Distro. Invalid Distro ID and/or Distro type.", "s2member-admin", "s2member"));
1185
  }
1186
  /**
1187
- * Disables an Amazon® S3/CloudFront Distro.
1188
  *
1189
  * @package s2Member\Files
1190
  * @since 110926
@@ -1222,23 +1222,23 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
1222
  return array("success" => true, "code" => null, "message" => null, "etag" => trim($cf_response["headers"]["etag"]), "xml" => trim($cf_response["body"]), "deployed" => ((stripos($cf_response["body"], "<Status>Deployed</Status>") !== false) ? true : false));
1223
 
1224
  else if(isset($cf_response["code"], $cf_response["message"]))
1225
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
1226
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to disable existing Amazon® CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1227
 
1228
  else // Else, we use a default error code and message.
1229
- return array("success" => false, "code" => -97, "message" => _x("Unable to disable existing Amazon® CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1230
  }
1231
  else // Else, we use a default error code and message.
1232
- return array("success" => false, "code" => -98, "message" => _x("Existing Amazon® CloudFront Distro cannot be disabled at this time. Still in a `pending` state. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon® CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon® CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
1233
  }
1234
  else // Else, we use a default error code and message.
1235
  return array("success" => true, "code" => null, "message" => null, "etag" => $distro_id_etag, "xml" => $distro_id_xml, "deployed" => ((stripos($distro_id_xml, "<Status>Deployed</Status>") !== false) ? true : false));
1236
  }
1237
  else // Else, we use a default error code and message.
1238
- return array("success" => false, "code" => -99, "message" => _x("Unable to disable existing Amazon® CloudFront Distro. Invalid Distro ID, ETag, or XML config.", "s2member-admin", "s2member"));
1239
  }
1240
  /**
1241
- * Deletes an Amazon® S3/CloudFront Distro.
1242
  *
1243
  * @package s2Member\Files
1244
  * @since 110926
@@ -1277,38 +1277,38 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
1277
  return /* Deleted successfully. */ array("success" => true, "code" => null, "message" => null);
1278
 
1279
  else if(isset($cf_response["code"], $cf_response["message"]))
1280
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
1281
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon® CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1282
 
1283
  else // Else, we use a default error code and message.
1284
- return array("success" => false, "code" => -94, "message" => _x("Unable to delete existing Amazon® CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1285
  }
1286
  else if(isset($cf_response["success"], $cf_response["deployed"]) && $cf_response["success"] && !$cf_response["deployed"])
1287
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
1288
- return array("success" => false, "code" => -95, "message" => _x("Existing Amazon® CloudFront Distro cannot be deleted at this time. Still in a `pending` state after having been disabled by s2Member. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon® CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon® CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
1289
 
1290
  else if(isset($cf_response["code"], $cf_response["message"]))
1291
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
1292
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to check status of existing Amazon® CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1293
 
1294
  else // Else, we use a default error code and message.
1295
- return array("success" => false, "code" => -96, "message" => _x("Unable to check status of existing Amazon® CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1296
  }
1297
  else if(isset($cf_response["code"], $cf_response["message"]))
1298
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
1299
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to disable existing Amazon® CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1300
 
1301
  else // Else, we use a default error code and message.
1302
- return array("success" => false, "code" => -97, "message" => _x("Unable to disable existing Amazon® CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1303
  }
1304
  else // Else, we use a default error code and message.
1305
- return array("success" => false, "code" => -98, "message" => _x("Existing Amazon® CloudFront Distro cannot be deleted at this time. Still in a `pending` state. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon® CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon® CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
1306
  }
1307
  else // Else, we use a default error code and message.
1308
- return array("success" => false, "code" => -99, "message" => _x("Unable to delete existing Amazon® CloudFront Distro. Invalid Distro ID or ETag.", "s2member-admin", "s2member"));
1309
  }
1310
  /**
1311
- * Creates an Amazon® S3/CloudFront Distro.
1312
  *
1313
  * @package s2Member\Files
1314
  * @since 110926
@@ -1346,14 +1346,14 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
1346
  return array("success" => true, "code" => null, "message" => null, "distro_downloads_id" => trim($cf_distro_downloads_id_tag[1]), "distro_downloads_dname" => trim($cf_distro_downloads_dname_tag[1]));
1347
 
1348
  else // Else, we use a default error code and message.
1349
- return array("success" => false, "code" => -97, "message" => _x("Unable to create/read Amazon® CloudFront Downloads Distro. Unexpected response.", "s2member-admin", "s2member"));
1350
  }
1351
  else if(isset($cf_response["code"], $cf_response["message"]))
1352
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
1353
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon® CloudFront Downloads Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1354
 
1355
  else // Else, we use a default error code and message.
1356
- return array("success" => false, "code" => -98, "message" => _x("Unable to create Amazon® CloudFront Downloads Distro. Connection failed.", "s2member-admin", "s2member"));
1357
  }
1358
 
1359
  else if /* Create a `streaming` Distro? A different XML schema. */($distro_type === "streaming")
@@ -1369,18 +1369,18 @@ if(!class_exists("c_ws_plugin__s2member_files_in"))
1369
  return array("success" => true, "code" => null, "message" => null, "distro_streaming_id" => trim($cf_distro_streaming_id_tag[1]), "distro_streaming_dname" => trim($cf_distro_streaming_dname_tag[1]));
1370
 
1371
  else // Else, we use a default error code and message.
1372
- return array("success" => false, "code" => -97, "message" => _x("Unable to create/read Amazon® CloudFront Streaming Distro. Unexpected response.", "s2member-admin", "s2member"));
1373
  }
1374
  else if(isset($cf_response["code"], $cf_response["message"]))
1375
- /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon® CloudFront API call. Feel free to exclude `%s` if you like. */
1376
- return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon® CloudFront Streaming Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1377
 
1378
  else // Else, we use a default error code and message.
1379
- return array("success" => false, "code" => -98, "message" => _x("Unable to create Amazon® CloudFront Streaming Distro. Connection failed.", "s2member-admin", "s2member"));
1380
  }
1381
  }
1382
  else // Else, we use a default error code and message.
1383
- return array("success" => false, "code" => -99, "message" => _x("Unable to create Amazon® CloudFront Distro. Invalid Distro type.", "s2member-admin", "s2member"));
1384
  }
1385
  }
1386
  }
516
  *
517
  * @param array $config Required. This is an array of configuration options associated with permissions being checked against the current User/Member; and also the actual URL generated by this routine.
518
  * Possible ``$config`` array elements: `file_download` *(required)*, `file_download_key`, `file_stream`, `file_inline`, `file_storage`, `file_remote`, `file_ssl`, `file_rewrite`, `file_rewrite_base`, `skip_confirmation`, `url_to_storage_source`, `count_against_user`, `check_user`.
519
+ * @param bool $get_streamer_array Optional. Defaults to `false`. If `true`, this function will return an array with the following elements: `streamer`, `file`, `url`. For further details, please review this section in your Dashboard: `s2Member -› Download Options -› JW Player & RTMP Protocol Examples`.
520
  * @return str A File Download URL string on success; or an array on success, with elements `streamer`, `file`, `url` when/if ``$get_streamer_array`` is true; else false on any type of failure.
521
  *
522
  * @see s2Member\API_Functions\s2member_file_download_url()
628
  return apply_filters("ws_plugin__s2member_check_file_download_key", ((isset($valid) && $valid) ? true : false), get_defined_vars());
629
  }
630
  /**
631
+ * Creates an Amazon S3 HMAC-SHA1 signature.
632
  *
633
  * @package s2Member\Files
634
  * @since 110524RC
635
  *
636
  * @param str $string Input string/data, to be signed by this routine.
637
+ * @return str An HMAC-SHA1 signature for Amazon S3.
638
  */
639
  public static function amazon_s3_sign($string = FALSE)
640
  {
643
  return c_ws_plugin__s2member_utils_strings::hmac_sha1_sign((string)$string, $s3c["secret_key"]);
644
  }
645
  /**
646
+ * Creates an Amazon S3 HMAC-SHA1 signature URL.
647
  *
648
  * @package s2Member\Files
649
  * @since 110926
654
  * @param bool $ssl Is this resource file to be served via SSL, or no?
655
  * @param str $basename The absolute basename of the resource file.
656
  * @param str $mimetype The MIME content-type of the resource file.
657
+ * @return str An HMAC-SHA1 signature URL for Amazon S3.
658
  */
659
  public static function amazon_s3_url($file = FALSE, $stream = FALSE, $inline = FALSE, $ssl = FALSE, $basename = FALSE, $mimetype = FALSE)
660
  {
677
  return add_query_arg(c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep (urlencode_deep(array("AWSAccessKeyId" => $s3c["access_key"], "Expires" => $s3c["expires"], "Signature" => $s3_signature))), $s3_url);
678
  }
679
  /**
680
+ * Auto-configures an Amazon S3 Bucket's ACLs.
681
  *
682
  * @package s2Member\Files
683
  * @since 110926
693
 
694
  $cfc["distros_s3_access_id"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distros_s3_access_id"];
695
 
696
+ if /* Must have Amazon S3 Bucket/Keys. */($s3c["bucket"] && $s3c["access_key"] && $s3c["secret_key"])
697
  {
698
  $s3_date = gmdate("D, d M Y H:i:s")." GMT";
699
  $s3_location = ((strtolower($s3c["bucket"]) !== $s3c["bucket"])) ? "/".$s3c["bucket"]."/?acl" : "/?acl";
726
  $s3_args = array("method" => "PUT", "redirection" => 0, "body" => $s3_policy_xml, "headers" => array("Host" => $s3_domain, "Content-Type" => "text/xml", "Date" => $s3_date, "X-Amz-Acl" => "public-read", "Authorization" => "AWS ".$s3c["access_key"].":".$s3_signature));
727
 
728
  if(($s3_response = c_ws_plugin__s2member_utils_urls::remote("https://".$s3_domain.$s3_location, false, array_merge($s3_args, array("timeout" => 20)), "array")) && $s3_response["code"] === 200)
729
+ return /* Successfully configured Amazon S3 Bucket ACLs and Policy. */ array("success" => true, "code" => null, "message" => null);
730
 
731
  else if(isset($s3_response["code"], $s3_response["message"]))
732
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon S3 API call. Feel free to exclude `%s` if you like. */
733
+ return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to update existing Amazon S3 Cross-Domain Policy. %s", "s2member-admin", "s2member"), $s3_response["message"]));
734
 
735
  else // Else, we use a default error code and message.
736
+ return array("success" => false, "code" => -94, "message" => _x("Unable to update existing Amazon S3 Cross-Domain Policy. Connection failed.", "s2member-admin", "s2member"));
737
  }
738
  else if(isset($s3_response["code"], $s3_response["message"]))
739
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon S3 API call. Feel free to exclude `%s` if you like. */
740
+ return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to update existing Amazon S3 Bucket Policy. %s", "s2member-admin", "s2member"), $s3_response["message"]));
741
 
742
  else // Else, we use a default error code and message.
743
+ return array("success" => false, "code" => -95, "message" => _x("Unable to update existing Amazon S3 Bucket Policy. Connection failed.", "s2member-admin", "s2member"));
744
  }
745
  else if(isset($s3_response["code"], $s3_response["message"]))
746
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon S3 API call. Feel free to exclude `%s` if you like. */
747
+ return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to update existing Amazon S3 Bucket ACLs. %s", "s2member-admin", "s2member"), $s3_response["message"]));
748
 
749
  else // Else, we use a default error code and message.
750
+ return array("success" => false, "code" => -96, "message" => _x("Unable to update existing Amazon S3 Bucket ACLs. Connection failed.", "s2member-admin", "s2member"));
751
  }
752
  else // Else, we use a default error code and message.
753
+ return array("success" => false, "code" => -97, "message" => _x("Unable to acquire/read existing Amazon S3 Bucket ACLs. Unexpected response.", "s2member-admin", "s2member"));
754
  }
755
  else if(isset($s3_response["code"], $s3_response["message"]))
756
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon S3 API call. Feel free to exclude `%s` if you like. */
757
+ return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon S3 Bucket ACLs. %s", "s2member-admin", "s2member"), $s3_response["message"]));
758
 
759
  else // Else, we use a default error code and message.
760
+ return array("success" => false, "code" => -98, "message" => _x("Unable to acquire existing Amazon S3 Bucket ACLs. Connection failed.", "s2member-admin", "s2member"));
761
  }
762
  else // Else, we use a default error code and message.
763
+ return array("success" => false, "code" => -99, "message" => _x("Unable to auto-configure existing Amazon S3 Bucket ACLs. Incomplete Amazon S3 configuration options. Missing one of: Amazon S3 Bucket, Access Key, or Secret Key.", "s2member-admin", "s2member"));
764
  }
765
  /**
766
+ * Creates an Amazon CloudFront HMAC-SHA1 signature.
767
  *
768
  * @package s2Member\Files
769
  * @since 110926
770
  *
771
  * @param str $string Input string/data, to be signed by this routine.
772
+ * @return str An HMAC-SHA1 signature for Amazon CloudFront.
773
  */
774
  public static function amazon_cf_sign($string = FALSE)
775
  {
778
  return c_ws_plugin__s2member_utils_strings::hmac_sha1_sign((string)$string, ($cfc["secret_key"] = $s3c["secret_key"]));
779
  }
780
  /**
781
+ * Creates an Amazon CloudFront RSA-SHA1 signature.
782
  *
783
  * @package s2Member\Files
784
  * @since 110926
785
  *
786
  * @param str $string Input string/data, to be signed by this routine.
787
+ * @return str|bool An RSA-SHA1 signature for Amazon CloudFront, else false on failure.
788
  */
789
  public static function amazon_cf_rsa_sign($string = FALSE)
790
  {
793
  return c_ws_plugin__s2member_utils_strings::rsa_sha1_sign((string)$string, $cfc["private_key"]);
794
  }
795
  /**
796
+ * Creates an Amazon CloudFront RSA-SHA1 signature URL.
797
  *
798
  * @package s2Member\Files
799
  * @since 110926
804
  * @param bool $ssl Is this resource file to be served via SSL, or no?
805
  * @param str $basename The absolute basename of the resource file.
806
  * @param str $mimetype The MIME content-type of the resource file.
807
+ * @return str An RSA-SHA1 signature URL for Amazon CloudFront.
808
  */
809
  public static function amazon_cf_url($file = FALSE, $stream = FALSE, $inline = FALSE, $ssl = FALSE, $basename = FALSE, $mimetype = FALSE)
810
  {
819
  $cfc["expires"] = strtotime("+".apply_filters("ws_plugin__s2member_amazon_cf_file_expires_time", "24 hours", get_defined_vars()));
820
 
821
  $cf_extn = /* Parses the file extension out so we can scan it in some special scenarios. */ strtolower(substr($file, strrpos($file, ".") + 1));
822
+ $cf_ip_res = /* Do NOT restrict access to a particular IP during `localhost` development. The IP may NOT be the same one Amazon CloudFront sees. */ (c_ws_plugin__s2member_utils_conds::is_localhost()) ? false : true;
823
  $cf_stream_extn_resource_exclusions = array_unique((array)apply_filters("ws_plugin__s2member_amazon_cf_file_streaming_extension_resource_exclusions", array("mp3" /* MP3 files should NOT include an extension in their resource reference. */), get_defined_vars()));
824
  $cf_resource = ($stream) ? ((in_array($cf_extn, $cf_stream_extn_resource_exclusions)) ? substr($file, 0, strrpos($file, ".")) : $file) : "http".(($ssl) ? "s" : "")."://".(($cfc["distro_downloads_cname"]) ? $cfc["distro_downloads_cname"] : $cfc["distro_downloads_dname"])."/".$url_e_file;
825
  $cf_url = ($stream) ? "rtmp".(($ssl) ? "e" : "")."://".(($cfc["distro_streaming_cname"]) ? $cfc["distro_streaming_cname"] : $cfc["distro_streaming_dname"])."/cfx/st/".$file : "http".(($ssl) ? "s" : "")."://".(($cfc["distro_downloads_cname"]) ? $cfc["distro_downloads_cname"] : $cfc["distro_downloads_dname"])."/".$url_e_file;
832
  return add_query_arg(c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(urlencode_deep(array("Policy" => $cf_base64_url_safe_policy, "Signature" => $cf_base64_url_safe_signature, "Key-Pair-Id" => $cfc["private_key_id"]))), $cf_url);
833
  }
834
  /**
835
+ * Auto-configures Amazon S3/CloudFront distros.
836
  *
837
  * @package s2Member\Files
838
  * @since 110926
850
  $cfc["access_key"] = $s3c["access_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_access_key"];
851
  $cfc["secret_key"] = $s3c["secret_key"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"];
852
 
853
+ if /* We MUST have an Amazon S3 Bucket and Keys. */($s3c["bucket"] && $s3c["access_key"] && $s3c["secret_key"])
854
  {
855
+ if /* We MUST have Amazon CloudFront Keys in order to auto-configure. */($cfc["private_key"] && $cfc["private_key_id"])
856
  {
857
  if(!$cfc["distro_downloads_id"] || ($cfc["distro_downloads_id"] && ($cf_get_response = c_ws_plugin__s2member_files_in::amazon_cf_get_distro($cfc["distro_downloads_id"], "downloads")) && ($cf_get_response["success"] || $cf_get_response["code"] === 404)))
858
  {
860
  $cf_distro_downloads_clear = /* Clear, ready for a new one. */ true;
861
 
862
  else if($cfc["distro_downloads_id"] && $cf_get_response && $cf_get_response["success"] && !$cf_get_response["deployed"])
863
+ return array("success" => false, "code" => -86, "message" => _x("Unable to delete existing Amazon CloudFront Downloads Distro. Still in a `pending` state. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
864
 
865
  else if($cfc["distro_downloads_id"] && $cf_get_response && $cf_get_response["success"] && $cf_get_response["deployed"] && ($cf_del_response = c_ws_plugin__s2member_files_in::amazon_cf_del_distro($cfc["distro_downloads_id"], $cf_get_response["etag"], $cf_get_response["xml"])) && $cf_del_response["success"])
866
  $cf_distro_downloads_clear = /* Clear, ready for a new one. */ true;
867
 
868
  else if(isset($cf_del_response["code"], $cf_del_response["message"]))
869
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
870
+ return array("success" => false, "code" => $cf_del_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon CloudFront Downloads Distro. %s", "s2member-admin", "s2member"), $cf_del_response["message"]));
871
 
872
  if /* Successfully cleared? Ready for a new one? */(isset($cf_distro_downloads_clear) && $cf_distro_downloads_clear)
873
  {
879
  $cf_distro_streaming_clear = /* Clear, ready for a new one. */ true;
880
 
881
  else if($cfc["distro_streaming_id"] && $cf_get_response && $cf_get_response["success"] && !$cf_get_response["deployed"])
882
+ return array("success" => false, "code" => -87, "message" => _x("Unable to delete existing Amazon CloudFront Streaming Distro. Still in a `pending` state. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
883
 
884
  else if($cfc["distro_streaming_id"] && $cf_get_response && $cf_get_response["success"] && $cf_get_response["deployed"] && ($cf_del_response = c_ws_plugin__s2member_files_in::amazon_cf_del_distro($cfc["distro_streaming_id"], $cf_get_response["etag"], $cf_get_response["xml"])) && $cf_del_response["success"])
885
  $cf_distro_streaming_clear = /* Clear, ready for a new one. */ true;
886
 
887
  else if(isset($cf_del_response["code"], $cf_del_response["message"]))
888
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
889
+ return array("success" => false, "code" => $cf_del_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon CloudFront Streaming Distro. %s", "s2member-admin", "s2member"), $cf_del_response["message"]));
890
 
891
  if /* Successfully cleared? Ready for a new one? */(isset($cf_distro_streaming_clear) && $cf_distro_streaming_clear)
892
  {
901
  $cf_distros_access_clear = /* Clear, ready for a new one. */ true;
902
 
903
  else if(isset($cf_del_response["code"], $cf_del_response["message"]))
904
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
905
+ return array("success" => false, "code" => $cf_del_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_del_response["message"]));
906
 
907
  if /* Successfully cleared? Ready for a new one? */(isset($cf_distros_access_clear) && $cf_distros_access_clear)
908
  {
939
  $cfc = array_merge($cfc, array("distros_auto_config_status" => "configured"));
940
  $cf_options = array("ws_plugin__s2member_amazon_cf_files_distros_auto_config_status" => "configured");
941
  c_ws_plugin__s2member_menu_pages::update_all_options( /* Now configured! */$cf_options, true, false, false, false, false);
942
+ return /* Successfully configured Amazon S3/CloudFront distros. */ array("success" => true, "code" => null, "message" => null);
943
  }
944
  if(isset($s3_response["code"], $s3_response["message"]))
945
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon S3 API call. Feel free to exclude `%s` if you like. */
946
+ return array("success" => false, "code" => $s3_response["code"], "message" => sprintf(_x("Unable to update existing Amazon S3 ACLs. %s", "s2member-admin", "s2member"), $s3_response["message"]));
947
 
948
  else // Else, we use a default error code and message.
949
+ return array("success" => false, "code" => -88, "message" => _x("Unable to update existing Amazon S3 ACLs. Connection failed.", "s2member-admin", "s2member"));
950
  }
951
  else if(isset($cf_response["code"], $cf_response["message"]))
952
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
953
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon CloudFront Streaming Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
954
 
955
  else // Else, we use a default error code and message.
956
+ return array("success" => false, "code" => -89, "message" => _x("Unable to create Amazon CloudFront Streaming Distro. Connection failed.", "s2member-admin", "s2member"));
957
  }
958
  else if(isset($cf_response["code"], $cf_response["message"]))
959
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
960
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon CloudFront Downloads Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
961
 
962
  else // Else, we use a default error code and message.
963
+ return array("success" => false, "code" => -90, "message" => _x("Unable to create Amazon CloudFront Downloads Distro. Connection failed.", "s2member-admin", "s2member"));
964
  }
965
  else if(isset($cf_response["code"], $cf_response["message"]))
966
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
967
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_response["message"]));
968
 
969
  else // Else, we use a default error code and message.
970
+ return array("success" => false, "code" => -91, "message" => _x("Unable to create Amazon CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
971
  }
972
  else // Else, we use a default error code and message.
973
+ return array("success" => false, "code" => -92, "message" => _x("Unable to clear existing Amazon CloudFront Origin Access Identity.", "s2member-admin", "s2member"));
974
  }
975
  else if(isset($cf_get_response["code"], $cf_get_response["message"]))
976
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
977
+ return array("success" => false, "code" => $cf_get_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_get_response["message"]));
978
 
979
  else // Else, we use a default error code and message.
980
+ return array("success" => false, "code" => -93, "message" => _x("Unable to acquire existing Amazon CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
981
  }
982
  else // Else, we use a default error code and message.
983
+ return array("success" => false, "code" => -94, "message" => _x("Unable to clear existing Amazon CloudFront Streaming Distro.", "s2member-admin", "s2member"));
984
  }
985
  else if(isset($cf_get_response["code"], $cf_get_response["message"]))
986
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
987
+ return array("success" => false, "code" => $cf_get_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon CloudFront Streaming Distro. %s", "s2member-admin", "s2member"), $cf_get_response["message"]));
988
 
989
  else // Else, we use a default error code and message.
990
+ return array("success" => false, "code" => -95, "message" => _x("Unable to acquire existing Amazon CloudFront Streaming Distro. Connection failed.", "s2member-admin", "s2member"));
991
  }
992
  else // Else, we use a default error code and message.
993
+ return array("success" => false, "code" => -96, "message" => _x("Unable to clear existing Amazon CloudFront Downloads Distro.", "s2member-admin", "s2member"));
994
  }
995
  else if(isset($cf_get_response["code"], $cf_get_response["message"]))
996
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
997
+ return array("success" => false, "code" => $cf_get_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon CloudFront Downloads Distro. %s", "s2member-admin", "s2member"), $cf_get_response["message"]));
998
 
999
  else // Else, we use a default error code and message.
1000
+ return array("success" => false, "code" => -97, "message" => _x("Unable to acquire existing Amazon CloudFront Downloads Distro. Connection failed.", "s2member-admin", "s2member"));
1001
  }
1002
  else // Else, we use a default error code and message.
1003
+ return array("success" => false, "code" => -98, "message" => _x("Unable to auto-configure Amazon CloudFront Distros. Incomplete Amazon CloudFront configuration options. Missing of one: Amazon CloudFront Private Key-Pair-ID, or Private Key file contents.", "s2member-admin", "s2member"));
1004
  }
1005
  else // Else, we use a default error code and message.
1006
+ return array("success" => false, "code" => -99, "message" => _x("Unable to auto-configure Amazon S3/CloudFront Distros. Incomplete Amazon S3 configuration options. Missing one of: Amazon S3 Bucket, Access Key, or Secret Key. You must provide s2Member with an Amazon S3 configuration before enabling CloudFront.", "s2member-admin", "s2member"));
1007
  }
1008
  /**
1009
+ * Acquires an Amazon S3/CloudFront Access Origin Identity.
1010
  *
1011
  * @package s2Member\Files
1012
  * @since 110926
1038
  if($cf_response["code"] === 200 && !empty($cf_response["headers"]["etag"]) && !empty($cf_response["body"]))
1039
  return array("success" => true, "code" => null, "message" => null, "etag" => trim($cf_response["headers"]["etag"]), "xml" => trim($cf_response["body"]));
1040
 
1041
+ else /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1042
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Existing Amazon CloudFront Origin Access Identity NOT found. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1043
  }
1044
  else if(isset($cf_response["code"], $cf_response["message"]))
1045
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1046
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1047
 
1048
  else // Else, we use a default error code and message.
1049
+ return array("success" => false, "code" => -98, "message" => _x("Unable to acquire existing Amazon CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
1050
  }
1051
  else // Else, we use a default error code and message.
1052
+ return array("success" => false, "code" => -99, "message" => _x("Unable to acquire existing Amazon CloudFront Origin Access Identity. Invalid Access ID.", "s2member-admin", "s2member"));
1053
  }
1054
  /**
1055
+ * Deletes an Amazon S3/CloudFront Access Origin Identity.
1056
  *
1057
  * @package s2Member\Files
1058
  * @since 110926
1085
  return /* Deleted successfully. */ array("success" => true, "code" => null, "message" => null);
1086
 
1087
  else if(isset($cf_response["code"], $cf_response["message"]))
1088
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1089
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1090
 
1091
  else // Else, we use a default error code and message.
1092
+ return array("success" => false, "code" => -98, "message" => _x("Unable to delete existing Amazon CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
1093
  }
1094
  else // Else, we use a default error code and message.
1095
+ return array("success" => false, "code" => -99, "message" => _x("Unable to delete existing Amazon CloudFront Origin Access Identity. Invalid Access ID, ETag, or XML config.", "s2member-admin", "s2member"));
1096
  }
1097
  /**
1098
+ * Creates an Amazon S3/CloudFront Access Origin Identity for all Distros.
1099
  *
1100
  * @package s2Member\Files
1101
  * @since 110926
1127
  return array("success" => true, "code" => null, "message" => null, "distros_access_id" => trim($cf_distros_access_id_tag[1]), "distros_s3_access_id" => trim($cf_distros_s3_access_id_tag[1]));
1128
 
1129
  else // Else, we use a default error code and message.
1130
+ return array("success" => false, "code" => -98, "message" => _x("Unable to create/read Amazon CloudFront Origin Access Identity. Unexpected response.", "s2member-admin", "s2member"));
1131
  }
1132
  else if(isset($cf_response["code"], $cf_response["message"]))
1133
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1134
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon CloudFront Origin Access Identity. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1135
 
1136
  else // Else, we use a default error code and message.
1137
+ return array("success" => false, "code" => -99, "message" => _x("Unable to create Amazon CloudFront Origin Access Identity. Connection failed.", "s2member-admin", "s2member"));
1138
  }
1139
  /**
1140
+ * Acquires an Amazon S3/CloudFront Distro.
1141
  *
1142
  * @package s2Member\Files
1143
  * @since 110926
1170
  if($cf_response["code"] === 200 && !empty($cf_response["headers"]["etag"]) && !empty($cf_response["body"]))
1171
  return array("success" => true, "code" => null, "message" => null, "etag" => trim($cf_response["headers"]["etag"]), "xml" => trim($cf_response["body"]), "deployed" => ((stripos($cf_response["body"], "<Status>Deployed</Status>") !== false) ? true : false));
1172
 
1173
+ else /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1174
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Existing Amazon CloudFront Distro NOT found. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1175
  }
1176
  else if(isset($cf_response["code"], $cf_response["message"]))
1177
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1178
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to acquire existing Amazon CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1179
 
1180
  else // Else, we use a default error code and message.
1181
+ return array("success" => false, "code" => -98, "message" => _x("Unable to acquire existing Amazon CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1182
  }
1183
  else // Else, we use a default error code and message.
1184
+ return array("success" => false, "code" => -99, "message" => _x("Unable to acquire existing Amazon CloudFront Distro. Invalid Distro ID and/or Distro type.", "s2member-admin", "s2member"));
1185
  }
1186
  /**
1187
+ * Disables an Amazon S3/CloudFront Distro.
1188
  *
1189
  * @package s2Member\Files
1190
  * @since 110926
1222
  return array("success" => true, "code" => null, "message" => null, "etag" => trim($cf_response["headers"]["etag"]), "xml" => trim($cf_response["body"]), "deployed" => ((stripos($cf_response["body"], "<Status>Deployed</Status>") !== false) ? true : false));
1223
 
1224
  else if(isset($cf_response["code"], $cf_response["message"]))
1225
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1226
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to disable existing Amazon CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1227
 
1228
  else // Else, we use a default error code and message.
1229
+ return array("success" => false, "code" => -97, "message" => _x("Unable to disable existing Amazon CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1230
  }
1231
  else // Else, we use a default error code and message.
1232
+ return array("success" => false, "code" => -98, "message" => _x("Existing Amazon CloudFront Distro cannot be disabled at this time. Still in a `pending` state. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
1233
  }
1234
  else // Else, we use a default error code and message.
1235
  return array("success" => true, "code" => null, "message" => null, "etag" => $distro_id_etag, "xml" => $distro_id_xml, "deployed" => ((stripos($distro_id_xml, "<Status>Deployed</Status>") !== false) ? true : false));
1236
  }
1237
  else // Else, we use a default error code and message.
1238
+ return array("success" => false, "code" => -99, "message" => _x("Unable to disable existing Amazon CloudFront Distro. Invalid Distro ID, ETag, or XML config.", "s2member-admin", "s2member"));
1239
  }
1240
  /**
1241
+ * Deletes an Amazon S3/CloudFront Distro.
1242
  *
1243
  * @package s2Member\Files
1244
  * @since 110926
1277
  return /* Deleted successfully. */ array("success" => true, "code" => null, "message" => null);
1278
 
1279
  else if(isset($cf_response["code"], $cf_response["message"]))
1280
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1281
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to delete existing Amazon CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1282
 
1283
  else // Else, we use a default error code and message.
1284
+ return array("success" => false, "code" => -94, "message" => _x("Unable to delete existing Amazon CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1285
  }
1286
  else if(isset($cf_response["success"], $cf_response["deployed"]) && $cf_response["success"] && !$cf_response["deployed"])
1287
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1288
+ return array("success" => false, "code" => -95, "message" => _x("Existing Amazon CloudFront Distro cannot be deleted at this time. Still in a `pending` state after having been disabled by s2Member. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
1289
 
1290
  else if(isset($cf_response["code"], $cf_response["message"]))
1291
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1292
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to check status of existing Amazon CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1293
 
1294
  else // Else, we use a default error code and message.
1295
+ return array("success" => false, "code" => -96, "message" => _x("Unable to check status of existing Amazon CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1296
  }
1297
  else if(isset($cf_response["code"], $cf_response["message"]))
1298
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1299
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to disable existing Amazon CloudFront Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1300
 
1301
  else // Else, we use a default error code and message.
1302
+ return array("success" => false, "code" => -97, "message" => _x("Unable to disable existing Amazon CloudFront Distro. Connection failed.", "s2member-admin", "s2member"));
1303
  }
1304
  else // Else, we use a default error code and message.
1305
+ return array("success" => false, "code" => -98, "message" => _x("Existing Amazon CloudFront Distro cannot be deleted at this time. Still in a `pending` state. Please wait 15 minutes, then try again. There is a certain process that s2Member must strictly adhere to when re-configuring your Amazon CloudFront Distros. You may have to tick the auto-configure checkbox again, and re-run s2Member's auto-configuration routine many times, because s2Member will likely run into several `pending` challenges, as it works to completely re-configure your Amazon CloudFront Distros for you. Thanks for your patience. Please wait 15 minutes, then try again.", "s2member-admin", "s2member"));
1306
  }
1307
  else // Else, we use a default error code and message.
1308
+ return array("success" => false, "code" => -99, "message" => _x("Unable to delete existing Amazon CloudFront Distro. Invalid Distro ID or ETag.", "s2member-admin", "s2member"));
1309
  }
1310
  /**
1311
+ * Creates an Amazon S3/CloudFront Distro.
1312
  *
1313
  * @package s2Member\Files
1314
  * @since 110926
1346
  return array("success" => true, "code" => null, "message" => null, "distro_downloads_id" => trim($cf_distro_downloads_id_tag[1]), "distro_downloads_dname" => trim($cf_distro_downloads_dname_tag[1]));
1347
 
1348
  else // Else, we use a default error code and message.
1349
+ return array("success" => false, "code" => -97, "message" => _x("Unable to create/read Amazon CloudFront Downloads Distro. Unexpected response.", "s2member-admin", "s2member"));
1350
  }
1351
  else if(isset($cf_response["code"], $cf_response["message"]))
1352
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1353
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon CloudFront Downloads Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1354
 
1355
  else // Else, we use a default error code and message.
1356
+ return array("success" => false, "code" => -98, "message" => _x("Unable to create Amazon CloudFront Downloads Distro. Connection failed.", "s2member-admin", "s2member"));
1357
  }
1358
 
1359
  else if /* Create a `streaming` Distro? A different XML schema. */($distro_type === "streaming")
1369
  return array("success" => true, "code" => null, "message" => null, "distro_streaming_id" => trim($cf_distro_streaming_id_tag[1]), "distro_streaming_dname" => trim($cf_distro_streaming_dname_tag[1]));
1370
 
1371
  else // Else, we use a default error code and message.
1372
+ return array("success" => false, "code" => -97, "message" => _x("Unable to create/read Amazon CloudFront Streaming Distro. Unexpected response.", "s2member-admin", "s2member"));
1373
  }
1374
  else if(isset($cf_response["code"], $cf_response["message"]))
1375
+ /* translators: In this translation, `%s` may be filled with an English message, which comes from the Amazon CloudFront API call. Feel free to exclude `%s` if you like. */
1376
+ return array("success" => false, "code" => $cf_response["code"], "message" => sprintf(_x("Unable to create Amazon CloudFront Streaming Distro. %s", "s2member-admin", "s2member"), $cf_response["message"]));
1377
 
1378
  else // Else, we use a default error code and message.
1379
+ return array("success" => false, "code" => -98, "message" => _x("Unable to create Amazon CloudFront Streaming Distro. Connection failed.", "s2member-admin", "s2member"));
1380
  }
1381
  }
1382
  else // Else, we use a default error code and message.
1383
+ return array("success" => false, "code" => -99, "message" => _x("Unable to create Amazon CloudFront Distro. Invalid Distro type.", "s2member-admin", "s2member"));
1384
  }
1385
  }
1386
  }
includes/classes/files.inc.php CHANGED
@@ -56,7 +56,7 @@ if(!class_exists("c_ws_plugin__s2member_files"))
56
  *
57
  * @param array $config Required. This is an array of configuration options associated with permissions being checked against the current User/Member; and also the actual URL generated by this routine.
58
  * Possible ``$config`` array elements: `file_download` *(required)*, `file_download_key`, `file_stream`, `file_inline`, `file_storage`, `file_remote`, `file_ssl`, `file_rewrite`, `file_rewrite_base`, `skip_confirmation`, `url_to_storage_source`, `count_against_user`, `check_user`.
59
- * @param bool $get_streamer_array Optional. Defaults to `false`. If `true`, this function will return an array with the following elements: `streamer`, `file`, `url`. For further details, please review this section in your Dashboard: `s2Member -› Download Options -› JW Player® & RTMP Protocol Examples`.
60
  * @return str A File Download URL string on success; or an array on success, with elements `streamer`, `file`, `url` when/if ``$get_streamer_array`` is true; else false on any type of failure.
61
  *
62
  * @see s2Member\API_Functions\s2member_file_download_url()
@@ -66,7 +66,7 @@ if(!class_exists("c_ws_plugin__s2member_files"))
66
  return c_ws_plugin__s2member_files_in::create_file_download_url($config, $get_streamer_array);
67
  }
68
  /**
69
- * Auto-configures an Amazon® S3 Bucket's ACLs.
70
  *
71
  * @package s2Member\Files
72
  * @since 110926
@@ -79,7 +79,7 @@ if(!class_exists("c_ws_plugin__s2member_files"))
79
  return c_ws_plugin__s2member_files_in::amazon_s3_auto_configure_acls();
80
  }
81
  /**
82
- * Auto-configures Amazon® CloudFront distros.
83
  *
84
  * @package s2Member\Files
85
  * @since 130209
@@ -178,7 +178,7 @@ if(!class_exists("c_ws_plugin__s2member_files"))
178
  *
179
  * @param obj $user Optional. A `WP_User` object. Defaults to the current User's object.
180
  * @param str $not_counting_this_particular_file Optional. If you want to exclude a particular file,
181
- * relative to the `/s2member-files/` directory, or relative to the root of your Amazon® S3 Bucket *(when applicable)*.
182
  * @param array $user_log Optional. Prevents another database connection *(i.e. the User's log does not need to be pulled again)*.
183
  * @param array $user_arc Optional. Prevents another database connection *(i.e. the User's archive does not need to be pulled again)*.
184
  * @return array An array with the following elements... File Downloads allowed for this User: (int)`allowed`, Download Period for this User in days: (int)`allowed_days`, Files downloaded by this User in the current Period: (int)`currently`, log of all Files downloaded in the current Period, with file names/dates: (array)`log`, archive of all Files downloaded in prior Periods, with file names/dates: (array)`archive`.
@@ -227,7 +227,7 @@ if(!class_exists("c_ws_plugin__s2member_files"))
227
  * @package s2Member\Files
228
  * @since 111026
229
  *
230
- * @param str $file Required. Location of the file, relative to the `/s2member-files/` directory, or relative to the root of your Amazon® S3 Bucket *(when applicable)*.
231
  * @param str|int $user_id Optional. If specified, s2Member will return total downloads by a particular User/Member, instead of collectively *(i.e among all Users/Members)*.
232
  * @param bool $check_archives_too Optional. Defaults to true. When true, s2Member checks its File Download Archive too, instead of ONLY looking at Files downloaded in the current Period. Period is based on your Basic Download Restrictions setting of allowed days across various Levels of Membership, for each respective User/Member. Or, if ``$user_id`` is specified, based solely on a specific User's `allowed_days`, configured in your Basic Download Restrictions, at the User's current Membership Level.
233
  * @return int The total for this particular ``$file``, based on configuration of function arguments.
@@ -262,7 +262,7 @@ if(!class_exists("c_ws_plugin__s2member_files"))
262
  * @package s2Member\Files
263
  * @since 111026
264
  *
265
- * @param str $file Required. Location of the file, relative to the `/s2member-files/` directory, or relative to the root of your Amazon® S3 Bucket *(when applicable)*.
266
  * @param str|int $user_id Optional. If specified, s2Member will return total downloads by a particular User/Member, instead of collectively *(i.e among all Users/Members)*.
267
  * @param bool $check_archives_too Optional. Defaults to true. When true, s2Member checks its File Download Archive too, instead of ONLY looking at Files downloaded in the current Period. Period is based on your Basic Download Restrictions setting of allowed days across various Levels of Membership, for each respective User/Member. Or, if ``$user_id`` is specified, based solely on a specific User's `allowed_days`, configured in your Basic Download Restrictions, at the User's current Membership Level.
268
  * @return int The total for this particular ``$file``, based on configuration of function arguments.
56
  *
57
  * @param array $config Required. This is an array of configuration options associated with permissions being checked against the current User/Member; and also the actual URL generated by this routine.
58
  * Possible ``$config`` array elements: `file_download` *(required)*, `file_download_key`, `file_stream`, `file_inline`, `file_storage`, `file_remote`, `file_ssl`, `file_rewrite`, `file_rewrite_base`, `skip_confirmation`, `url_to_storage_source`, `count_against_user`, `check_user`.
59
+ * @param bool $get_streamer_array Optional. Defaults to `false`. If `true`, this function will return an array with the following elements: `streamer`, `file`, `url`. For further details, please review this section in your Dashboard: `s2Member -› Download Options -› JW Player & RTMP Protocol Examples`.
60
  * @return str A File Download URL string on success; or an array on success, with elements `streamer`, `file`, `url` when/if ``$get_streamer_array`` is true; else false on any type of failure.
61
  *
62
  * @see s2Member\API_Functions\s2member_file_download_url()
66
  return c_ws_plugin__s2member_files_in::create_file_download_url($config, $get_streamer_array);
67
  }
68
  /**
69
+ * Auto-configures an Amazon S3 Bucket's ACLs.
70
  *
71
  * @package s2Member\Files
72
  * @since 110926
79
  return c_ws_plugin__s2member_files_in::amazon_s3_auto_configure_acls();
80
  }
81
  /**
82
+ * Auto-configures Amazon CloudFront distros.
83
  *
84
  * @package s2Member\Files
85
  * @since 130209
178
  *
179
  * @param obj $user Optional. A `WP_User` object. Defaults to the current User's object.
180
  * @param str $not_counting_this_particular_file Optional. If you want to exclude a particular file,
181
+ * relative to the `/s2member-files/` directory, or relative to the root of your Amazon S3 Bucket *(when applicable)*.
182
  * @param array $user_log Optional. Prevents another database connection *(i.e. the User's log does not need to be pulled again)*.
183
  * @param array $user_arc Optional. Prevents another database connection *(i.e. the User's archive does not need to be pulled again)*.
184
  * @return array An array with the following elements... File Downloads allowed for this User: (int)`allowed`, Download Period for this User in days: (int)`allowed_days`, Files downloaded by this User in the current Period: (int)`currently`, log of all Files downloaded in the current Period, with file names/dates: (array)`log`, archive of all Files downloaded in prior Periods, with file names/dates: (array)`archive`.
227
  * @package s2Member\Files
228
  * @since 111026
229
  *
230
+ * @param str $file Required. Location of the file, relative to the `/s2member-files/` directory, or relative to the root of your Amazon S3 Bucket *(when applicable)*.
231
  * @param str|int $user_id Optional. If specified, s2Member will return total downloads by a particular User/Member, instead of collectively *(i.e among all Users/Members)*.
232
  * @param bool $check_archives_too Optional. Defaults to true. When true, s2Member checks its File Download Archive too, instead of ONLY looking at Files downloaded in the current Period. Period is based on your Basic Download Restrictions setting of allowed days across various Levels of Membership, for each respective User/Member. Or, if ``$user_id`` is specified, based solely on a specific User's `allowed_days`, configured in your Basic Download Restrictions, at the User's current Membership Level.
233
  * @return int The total for this particular ``$file``, based on configuration of function arguments.
262
  * @package s2Member\Files
263
  * @since 111026
264
  *
265
+ * @param str $file Required. Location of the file, relative to the `/s2member-files/` directory, or relative to the root of your Amazon S3 Bucket *(when applicable)*.
266
  * @param str|int $user_id Optional. If specified, s2Member will return total downloads by a particular User/Member, instead of collectively *(i.e among all Users/Members)*.
267
  * @param bool $check_archives_too Optional. Defaults to true. When true, s2Member checks its File Download Archive too, instead of ONLY looking at Files downloaded in the current Period. Period is based on your Basic Download Restrictions setting of allowed days across various Levels of Membership, for each respective User/Member. Or, if ``$user_id`` is specified, based solely on a specific User's `allowed_days`, configured in your Basic Download Restrictions, at the User's current Membership Level.
268
  * @return int The total for this particular ``$file``, based on configuration of function arguments.
includes/classes/installation.inc.php CHANGED
@@ -94,7 +94,7 @@ if(!class_exists("c_ws_plugin__s2member_installation"))
94
  if(!$v || !version_compare($v, "110912", ">=") && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["filter_wp_query"] === array("all"))
95
  // s2Member v110912 changed the way the "all" option for Alternative Views was handled.
96
  {
97
- $notice = '<strong>IMPORTANT:</strong> This version of s2Member® changes the way your <code>Alternative View Protections</code> work. Please review your options under: <code>s2Member -› Restriction Options -› Alternative View Protections</code>.';
98
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, array("blog|network:plugins.php", "blog|network:ws-plugin--s2member-start", "blog|network:ws-plugin--s2member-mms-ops", "blog|network:ws-plugin--s2member-gen-ops", "blog|network:ws-plugin--s2member-res-ops"));
99
  }
100
 
@@ -102,10 +102,10 @@ if(!class_exists("c_ws_plugin__s2member_installation"))
102
  {
103
  c_ws_plugin__s2member_menu_pages::update_all_options(array("ws_plugin__s2member_gateway_debug_logs" => "0", "ws_plugin__s2member_gateway_debug_logs_extensive" => "0"), true, false, false, false, false);
104
 
105
- $notice = '<strong>IMPORTANT:</strong> This version of s2Member® disables s2Member\'s debug logging by default (for added security). Please see: <a href="'.esc_attr(admin_url("/admin.php?page=ws-plugin--s2member-logs")).'">s2Member® -› Log Files (Debug) -› Configuration</a> for further details.';
106
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, array("blog|network:plugins.php", "blog|network:ws-plugin--s2member-start", "blog|network:ws-plugin--s2member-mms-ops", "blog|network:ws-plugin--s2member-gen-ops", "blog|network:ws-plugin--s2member-res-ops"));
107
 
108
- $notice = '<strong>IMPORTANT / Regarding s2Member® Security Badges:</strong> If debug logging is enabled, your site will no longer qualify for an s2Member® Security Badge until you disable logging (and you MUST also download, and then delete any existing log files from the past). Please see KB Article: <a href="http://www.s2member.com/kb/security-badges/" target="_blank" rel="external">s2Member® Security Badges</a> for further details. If you have existing s2Member® log files, you will need to delete those files from the server before your s2Member® Security Badge can be re-enabled. s2Member® stores log files here: <code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["logs_dir"])).'</code>. See also: <a href="'.esc_attr(admin_url("/admin.php?page=ws-plugin--s2member-logs")).'">s2Member® -› Log Files (Debug) -› Configuration</a> for further details.';
109
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, array("blog|network:plugins.php", "blog|network:ws-plugin--s2member-start", "blog|network:ws-plugin--s2member-mms-ops", "blog|network:ws-plugin--s2member-gen-ops", "blog|network:ws-plugin--s2member-res-ops"));
110
  }
111
 
@@ -119,7 +119,7 @@ if(!class_exists("c_ws_plugin__s2member_installation"))
119
  }
120
  else // Otherwise (initial activation); we'll help the Site Owner out by giving them a link to the Quick Start Guide.
121
  {
122
- $notice = '<strong>Note:</strong> s2Member adds some new data columns to your list of Users/Members. If your list gets overcrowded, please use the <strong>Screen Options</strong> tab <em>(upper right-hand corner)</em>. With WordPress® Screen Options, you can add/remove specific data columns; thereby making the most important data easier to read. For example, if you create Custom Registration/Profile Fields with s2Member, those Custom Fields will result in new data columns; which can cause your list of Users/Members to become nearly unreadable. So just use the Screen Options tab to clean things up.';
123
 
124
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, "blog:users.php", false, false, true);
125
 
94
  if(!$v || !version_compare($v, "110912", ">=") && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["filter_wp_query"] === array("all"))
95
  // s2Member v110912 changed the way the "all" option for Alternative Views was handled.
96
  {
97
+ $notice = '<strong>IMPORTANT:</strong> This version of s2Member changes the way your <code>Alternative View Protections</code> work. Please review your options under: <code>s2Member -› Restriction Options -› Alternative View Protections</code>.';
98
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, array("blog|network:plugins.php", "blog|network:ws-plugin--s2member-start", "blog|network:ws-plugin--s2member-mms-ops", "blog|network:ws-plugin--s2member-gen-ops", "blog|network:ws-plugin--s2member-res-ops"));
99
  }
100
 
102
  {
103
  c_ws_plugin__s2member_menu_pages::update_all_options(array("ws_plugin__s2member_gateway_debug_logs" => "0", "ws_plugin__s2member_gateway_debug_logs_extensive" => "0"), true, false, false, false, false);
104
 
105
+ $notice = '<strong>IMPORTANT:</strong> This version of s2Member disables s2Member\'s debug logging by default (for added security). Please see: <a href="'.esc_attr(admin_url("/admin.php?page=ws-plugin--s2member-logs")).'">s2Member -› Log Files (Debug) -› Configuration</a> for further details.';
106
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, array("blog|network:plugins.php", "blog|network:ws-plugin--s2member-start", "blog|network:ws-plugin--s2member-mms-ops", "blog|network:ws-plugin--s2member-gen-ops", "blog|network:ws-plugin--s2member-res-ops"));
107
 
108
+ $notice = '<strong>IMPORTANT / Regarding s2Member Security Badges:</strong> If debug logging is enabled, your site will no longer qualify for an s2Member Security Badge until you disable logging (and you MUST also download, and then delete any existing log files from the past). Please see KB Article: <a href="http://www.s2member.com/kb/security-badges/" target="_blank" rel="external">s2Member Security Badges</a> for further details. If you have existing s2Member log files, you will need to delete those files from the server before your s2Member Security Badge can be re-enabled. s2Member stores log files here: <code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["logs_dir"])).'</code>. See also: <a href="'.esc_attr(admin_url("/admin.php?page=ws-plugin--s2member-logs")).'">s2Member -› Log Files (Debug) -› Configuration</a> for further details.';
109
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, array("blog|network:plugins.php", "blog|network:ws-plugin--s2member-start", "blog|network:ws-plugin--s2member-mms-ops", "blog|network:ws-plugin--s2member-gen-ops", "blog|network:ws-plugin--s2member-res-ops"));
110
  }
111
 
119
  }
120
  else // Otherwise (initial activation); we'll help the Site Owner out by giving them a link to the Quick Start Guide.
121
  {
122
+ $notice = '<strong>Note:</strong> s2Member adds some new data columns to your list of Users/Members. If your list gets overcrowded, please use the <strong>Screen Options</strong> tab <em>(upper right-hand corner)</em>. With WordPress Screen Options, you can add/remove specific data columns; thereby making the most important data easier to read. For example, if you create Custom Registration/Profile Fields with s2Member, those Custom Fields will result in new data columns; which can cause your list of Users/Members to become nearly unreadable. So just use the Screen Options tab to clean things up.';
123
 
124
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, "blog:users.php", false, false, true);
125
 
includes/classes/list-servers.inc.php CHANGED
@@ -66,7 +66,7 @@ if (!class_exists ("c_ws_plugin__s2member_list_servers"))
66
  *
67
  * @todo Integrate {@link https://labs.aweber.com/docs/php-library-walkthrough AWeber's API}.
68
  * @todo Add a separate option for mail debugging; or consolidate?
69
- * @todo Integrate AWeber® API (much like the MailChimp® API).
70
  */
71
  public static function process_list_servers ($role = FALSE, $level = FALSE, $login = FALSE, $pass = FALSE, $email = FALSE, $fname = FALSE, $lname = FALSE, $ip = FALSE, $opt_in = FALSE, $double_opt_in = TRUE, $user_id = FALSE)
72
  {
@@ -85,10 +85,10 @@ if (!class_exists ("c_ws_plugin__s2member_list_servers"))
85
 
86
  if (!empty ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["mailchimp_api_key"]) && !empty ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $level . "_mailchimp_list_ids"]))
87
  {
88
- if /* Include the MailChimp® API Class here. */ (!class_exists ("NC_MCAPI"))
89
- include_once /* MailChimp® API (no-conflict version). */ dirname (dirname (__FILE__)) . "/externals/mailchimp/nc-mcapi.inc.php";
90
 
91
- $mcapi = /* MailChimp® API (no-conflict). */ new NC_MCAPI ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["mailchimp_api_key"], true);
92
 
93
  foreach (preg_split ("/[\r\n\t;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $level . "_mailchimp_list_ids"]) as $mailchimp_list)
94
  {
@@ -155,7 +155,7 @@ if (!class_exists ("c_ws_plugin__s2member_list_servers"))
155
  $aweber["pass_inclusion"] = (apply_filters ("ws_plugin__s2member_aweber_pass_inclusion", false, get_defined_vars ()) && $pass) ? "\nPass: " . $pass : false;
156
  $buyer = ($fname || $lname) ? trim ($fname . " " . $lname) : /* Must have. AWeber's PayPal Email Parser chokes on an empty value. */ ucwords (preg_replace ("/^(.+?)@.+/", "$1", $email));
157
 
158
- if ($aweber["wp_mail_response"] = wp_mail ($aweber["list_id"] . "@aweber.com", // AWeber® List ID converts to email address @aweber.com.
159
  ($aweber["wp_mail_sbj"] = apply_filters ("ws_plugin__s2member_aweber_sbj", "s2Member Subscription Request", get_defined_vars ())), // These Filters make it possible to customize these emails.
160
  ($aweber["wp_mail_msg"] = apply_filters ("ws_plugin__s2member_aweber_msg", "s2Member Subscription Request\ns2Member w/ PayPal Email ID\nAd Tracking: s2Member-" . ((is_multisite () && !is_main_site ()) ? $current_blog->domain . $current_blog->path : $_SERVER["HTTP_HOST"]) . "\nEMail Address: " . $email . "\nBuyer: " . $buyer . "\nFull Name: " . trim ($fname . " " . $lname) . "\nFirst Name: " . $fname . "\nLast Name: " . $lname . "\nIP Address: " . $ip . "\nUser ID: " . $user_id . "\nLogin: " . $login . $aweber["pass_inclusion"] . "\nRole: " . $role . "\nLevel: " . $level . "\nCCaps: " . $ccaps . "\n - end.", get_defined_vars ())),
161
  ($aweber["wp_mail_headers"] = "From: \"" . preg_replace ('/"/', "'", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_name"]) . "\" <" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"] . ">" . (($aweber["bcc"]) ? "\r\nBcc: " . $aweber["bcc"] : "") . "\r\nContent-Type: text/plain; charset=UTF-8")))
@@ -213,7 +213,7 @@ if (!class_exists ("c_ws_plugin__s2member_list_servers"))
213
  *
214
  * @todo Integrate {@link https://labs.aweber.com/docs/php-library-walkthrough AWeber's API}.
215
  * @todo Add a separate option for mail debugging; or consolidate?
216
- * @todo Integrate AWeber® API (much like the MailChimp® API).
217
  */
218
  public static function process_list_server_removals ($role = FALSE, $level = FALSE, $login = FALSE, $pass = FALSE, $email = FALSE, $fname = FALSE, $lname = FALSE, $ip = FALSE, $opt_out = FALSE, $user_id = FALSE)
219
  {
@@ -232,10 +232,10 @@ if (!class_exists ("c_ws_plugin__s2member_list_servers"))
232
 
233
  if (!empty ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["mailchimp_api_key"]) && !empty ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $level . "_mailchimp_list_ids"]))
234
  {
235
- if /* Include the MailChimp® API Class here. */ (!class_exists ("NC_MCAPI"))
236
- include_once /* MailChimp® API (no-conflict version). */ dirname (dirname (__FILE__)) . "/externals/mailchimp/nc-mcapi.inc.php";
237
 
238
- $mcapi = /* MailChimp® API (no-conflict). */ new NC_MCAPI ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["mailchimp_api_key"], true);
239
 
240
  foreach (preg_split ("/[\r\n\t;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $level . "_mailchimp_list_ids"]) as $mailchimp_list)
241
  {
@@ -281,8 +281,8 @@ if (!class_exists ("c_ws_plugin__s2member_list_servers"))
281
  c_ws_plugin__s2member_email_configs::email_config (); // Email configs MUST be ON for removal requests.
282
  // The `From:` address MUST match AWeber account. See: <http://www.aweber.com/faq/questions/62/Can+I+Unsubscribe+People+Via+Email%3F>.
283
 
284
- if ($aweber["wp_mail_removal_response"] = wp_mail ($aweber["list_id"] . "@aweber.com", // AWeber® List ID converts to email address @aweber.com.
285
- ($aweber["wp_mail_removal_sbj"] = apply_filters ("ws_plugin__s2member_aweber_removal_sbj", "REMOVE#" . $email . "#s2Member#" . $aweber["list_id"], get_defined_vars ())), // Bug fix. AWeber® does not like dots (possibly other chars) in the Ad Tracking field. Now using just: `s2Member`.
286
  ($aweber["wp_mail_removal_msg"] = "REMOVE"), ($aweber["wp_mail_removal_headers"] = "From: \"" . preg_replace ('/"/', "'", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_name"]) . "\" <" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"] . ">" . (($aweber["removal_bcc"]) ? "\r\nBcc: " . $aweber["removal_bcc"] : "") . "\r\nContent-Type: text/plain; charset=UTF-8")))
287
  $aweber["wp_mail_removal_success"] = $removal_success = true; // Flag indicating that we DO have a successful removal; affects the function's overall return value.
288
 
@@ -331,7 +331,7 @@ if (!class_exists ("c_ws_plugin__s2member_list_servers"))
331
  * @attaches-to ``add_action("ws_plugin__s2member_during_collective_mods");``
332
  * @attaches-to ``add_action("ws_plugin__s2member_during_collective_eots");``
333
  *
334
- * @param int|str $user_id Required. A WordPress® User ID, numeric string or integer.
335
  * @param array $vars Required. An array of defined variables passed by the calling Hook.
336
  * @param str $event Required. A specific event that triggered this call from the Action Hook.
337
  * @param str $event_spec Required. A specific event specification *(a broader classification)*.
66
  *
67
  * @todo Integrate {@link https://labs.aweber.com/docs/php-library-walkthrough AWeber's API}.
68
  * @todo Add a separate option for mail debugging; or consolidate?
69
+ * @todo Integrate AWeber API (much like the MailChimp API).
70
  */
71
  public static function process_list_servers ($role = FALSE, $level = FALSE, $login = FALSE, $pass = FALSE, $email = FALSE, $fname = FALSE, $lname = FALSE, $ip = FALSE, $opt_in = FALSE, $double_opt_in = TRUE, $user_id = FALSE)
72
  {
85
 
86
  if (!empty ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["mailchimp_api_key"]) && !empty ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $level . "_mailchimp_list_ids"]))
87
  {
88
+ if /* Include the MailChimp API Class here. */ (!class_exists ("NC_MCAPI"))
89
+ include_once /* MailChimp API (no-conflict version). */ dirname (dirname (__FILE__)) . "/externals/mailchimp/nc-mcapi.inc.php";
90
 
91
+ $mcapi = /* MailChimp API (no-conflict). */ new NC_MCAPI ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["mailchimp_api_key"], true);
92
 
93
  foreach (preg_split ("/[\r\n\t;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $level . "_mailchimp_list_ids"]) as $mailchimp_list)
94
  {
155
  $aweber["pass_inclusion"] = (apply_filters ("ws_plugin__s2member_aweber_pass_inclusion", false, get_defined_vars ()) && $pass) ? "\nPass: " . $pass : false;
156
  $buyer = ($fname || $lname) ? trim ($fname . " " . $lname) : /* Must have. AWeber's PayPal Email Parser chokes on an empty value. */ ucwords (preg_replace ("/^(.+?)@.+/", "$1", $email));
157
 
158
+ if ($aweber["wp_mail_response"] = wp_mail ($aweber["list_id"] . "@aweber.com", // AWeber List ID converts to email address @aweber.com.
159
  ($aweber["wp_mail_sbj"] = apply_filters ("ws_plugin__s2member_aweber_sbj", "s2Member Subscription Request", get_defined_vars ())), // These Filters make it possible to customize these emails.
160
  ($aweber["wp_mail_msg"] = apply_filters ("ws_plugin__s2member_aweber_msg", "s2Member Subscription Request\ns2Member w/ PayPal Email ID\nAd Tracking: s2Member-" . ((is_multisite () && !is_main_site ()) ? $current_blog->domain . $current_blog->path : $_SERVER["HTTP_HOST"]) . "\nEMail Address: " . $email . "\nBuyer: " . $buyer . "\nFull Name: " . trim ($fname . " " . $lname) . "\nFirst Name: " . $fname . "\nLast Name: " . $lname . "\nIP Address: " . $ip . "\nUser ID: " . $user_id . "\nLogin: " . $login . $aweber["pass_inclusion"] . "\nRole: " . $role . "\nLevel: " . $level . "\nCCaps: " . $ccaps . "\n - end.", get_defined_vars ())),
161
  ($aweber["wp_mail_headers"] = "From: \"" . preg_replace ('/"/', "'", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_name"]) . "\" <" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"] . ">" . (($aweber["bcc"]) ? "\r\nBcc: " . $aweber["bcc"] : "") . "\r\nContent-Type: text/plain; charset=UTF-8")))
213
  *
214
  * @todo Integrate {@link https://labs.aweber.com/docs/php-library-walkthrough AWeber's API}.
215
  * @todo Add a separate option for mail debugging; or consolidate?
216
+ * @todo Integrate AWeber API (much like the MailChimp API).
217
  */
218
  public static function process_list_server_removals ($role = FALSE, $level = FALSE, $login = FALSE, $pass = FALSE, $email = FALSE, $fname = FALSE, $lname = FALSE, $ip = FALSE, $opt_out = FALSE, $user_id = FALSE)
219
  {
232
 
233
  if (!empty ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["mailchimp_api_key"]) && !empty ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $level . "_mailchimp_list_ids"]))
234
  {
235
+ if /* Include the MailChimp API Class here. */ (!class_exists ("NC_MCAPI"))
236
+ include_once /* MailChimp API (no-conflict version). */ dirname (dirname (__FILE__)) . "/externals/mailchimp/nc-mcapi.inc.php";
237
 
238
+ $mcapi = /* MailChimp API (no-conflict). */ new NC_MCAPI ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["mailchimp_api_key"], true);
239
 
240
  foreach (preg_split ("/[\r\n\t;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $level . "_mailchimp_list_ids"]) as $mailchimp_list)
241
  {
281
  c_ws_plugin__s2member_email_configs::email_config (); // Email configs MUST be ON for removal requests.
282
  // The `From:` address MUST match AWeber account. See: <http://www.aweber.com/faq/questions/62/Can+I+Unsubscribe+People+Via+Email%3F>.
283
 
284
+ if ($aweber["wp_mail_removal_response"] = wp_mail ($aweber["list_id"] . "@aweber.com", // AWeber List ID converts to email address @aweber.com.
285
+ ($aweber["wp_mail_removal_sbj"] = apply_filters ("ws_plugin__s2member_aweber_removal_sbj", "REMOVE#" . $email . "#s2Member#" . $aweber["list_id"], get_defined_vars ())), // Bug fix. AWeber does not like dots (possibly other chars) in the Ad Tracking field. Now using just: `s2Member`.
286
  ($aweber["wp_mail_removal_msg"] = "REMOVE"), ($aweber["wp_mail_removal_headers"] = "From: \"" . preg_replace ('/"/', "'", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_name"]) . "\" <" . $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"] . ">" . (($aweber["removal_bcc"]) ? "\r\nBcc: " . $aweber["removal_bcc"] : "") . "\r\nContent-Type: text/plain; charset=UTF-8")))
287
  $aweber["wp_mail_removal_success"] = $removal_success = true; // Flag indicating that we DO have a successful removal; affects the function's overall return value.
288
 
331
  * @attaches-to ``add_action("ws_plugin__s2member_during_collective_mods");``
332
  * @attaches-to ``add_action("ws_plugin__s2member_during_collective_eots");``
333
  *
334
+ * @param int|str $user_id Required. A WordPress User ID, numeric string or integer.
335
  * @param array $vars Required. An array of defined variables passed by the calling Hook.
336
  * @param str $event Required. A specific event that triggered this call from the Action Hook.
337
  * @param str $event_spec Required. A specific event specification *(a broader classification)*.
includes/classes/login-checks.inc.php ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Login checks.
4
+ *
5
+ * Copyright: © 2009-2011
6
+ * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
7
+ * (coded in the USA)
8
+ *
9
+ * Released under the terms of the GNU General Public License.
10
+ * You should have received a copy of the GNU General Public License,
11
+ * along with this software. In the main directory, see: /licensing/
12
+ * If not, see: {@link http://www.gnu.org/licenses/}.
13
+ *
14
+ * @package s2Member\Login_Checks
15
+ * @since 131025
16
+ */
17
+ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
18
+ exit ("Do not access this file directly.");
19
+
20
+ if (!class_exists ("c_ws_plugin__s2member_login_checks"))
21
+ {
22
+ /**
23
+ * Login checks.
24
+ *
25
+ * @package s2Member\Login_Checks
26
+ * @since 131025
27
+ */
28
+ class c_ws_plugin__s2member_login_checks
29
+ {
30
+ /**
31
+ * Assists in multisite User authentication.
32
+ *
33
+ * @package s2Member\Login_Checks
34
+ * @since 131025
35
+ *
36
+ * @attaches-to ``add_filter("wp_authenticate_user");``
37
+ *
38
+ * @param WP_User|WP_Error Expects either a WP_User or WP_Error object passed in by the Filter.
39
+ * @return WP_User|WP_Error WP_User or WP_Error object (if there was a problem).
40
+ */
41
+ public static function ms_wp_authenticate_user ($user_or_wp_error = FALSE)
42
+ {
43
+ if(!is_multisite()) return $user_or_wp_error;
44
+
45
+ foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
46
+ do_action ("ws_plugin__s2member_before_ms_wp_authenticate_user", get_defined_vars ());
47
+ unset /* Unset defined __refs, __v. */ ($__refs, $__v);
48
+
49
+ if(is_a($user_or_wp_error, "WP_User") && ($user = $user_or_wp_error) && $user->ID && !is_super_admin($user->ID) && !in_array(get_current_blog_id(), array_keys(get_blogs_of_user($user->ID)), TRUE))
50
+ $user_or_wp_error = new WP_Error("invalid_username", _x("<strong>ERROR</strong>: Invalid username for this site.", "s2member-front", "s2member"));
51
+
52
+ return apply_filters ("ws_plugin__s2member_ms_wp_authenticate_user", $user_or_wp_error, get_defined_vars ());
53
+ }
54
+
55
+ /**
56
+ * Assists in User authentication (stops max simultaneous logins).
57
+ *
58
+ * @package s2Member\Login_Checks
59
+ * @since 131025
60
+ *
61
+ * @attaches-to ``add_filter("wp_authenticate_user");``
62
+ *
63
+ * @param WP_User|WP_Error Expects either a WP_User or WP_Error object passed in by the Filter.
64
+ * @return WP_User|WP_Error WP_User or WP_Error object (if there was a problem).
65
+ */
66
+ public static function stop_simultaneous_logins ($user_or_wp_error = FALSE)
67
+ {
68
+ if(!($max = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_simultaneous_logins"]))
69
+ return $user_or_wp_error; // Simultaneous login monitoring not enabled here.
70
+
71
+ foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
72
+ do_action ("ws_plugin__s2member_before_stop_simultaneous_logins", get_defined_vars ());
73
+ unset /* Unset defined __refs, __v. */ ($__refs, $__v);
74
+
75
+ if(is_a($user_or_wp_error, "WP_User") && ($user = $user_or_wp_error) && $user->ID && !is_super_admin($user->ID) && c_ws_plugin__s2member_login_checks::get_simultaneous_logins($user->user_login) + 1 > $max)
76
+ $user_or_wp_error = new WP_Error("max_simultaneous_logins", sprintf(_x('<strong>ERROR</strong>: Max simultaneous logins for username: %1$s. Please wait %2$s and try again.', "s2member-front", "s2member"), $user->user_login, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_simultaneous_logins_timeout"]));
77
+
78
+ return apply_filters ("ws_plugin__s2member_stop_simultaneous_logins", $user_or_wp_error, get_defined_vars ());
79
+ }
80
+
81
+ /**
82
+ * Monitors simultaneous logins (updates timer on each page view).
83
+ *
84
+ * @package s2Member\Login_Checks
85
+ * @since 131025
86
+ *
87
+ * @attaches-to ``add_action("init");``
88
+ *
89
+ * @param WP_User|WP_Error Expects either a WP_User or WP_Error object passed in by the Filter.
90
+ * @return WP_User|WP_Error WP_User or WP_Error object (if there was a problem).
91
+ */
92
+ public static function monitor_simultaneous_logins ()
93
+ {
94
+ if(!is_user_logged_in() || is_super_admin())
95
+ return; // Nothing to do here.
96
+
97
+ if(!($max = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_simultaneous_logins"]))
98
+ return; // Simultaneous login monitoring not enabled here.
99
+
100
+ foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
101
+ do_action ("ws_plugin__s2member_before_monitor_simultaneous_logins", get_defined_vars ());
102
+ unset /* Unset defined __refs, __v. */ ($__refs, $__v);
103
+
104
+ $user = wp_get_current_user();
105
+ $username = $user->user_login; // The username.
106
+ c_ws_plugin__s2member_login_checks::update_simultaneous_logins($username, $user, 'timer');
107
+ }
108
+
109
+ /**
110
+ * Handles simultaneous logouts.
111
+ *
112
+ * @package s2Member\Login_Checks
113
+ * @since 131025
114
+ *
115
+ * @attaches-to ``add_action("clear_auth_cookie");``
116
+ */
117
+ public static function simultaneous_logout ()
118
+ {
119
+ if(!is_user_logged_in() || is_super_admin())
120
+ return; // Nothing to do here.
121
+
122
+ if(!($max = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_simultaneous_logins"]))
123
+ return; // Simultaneous login monitoring not enabled here.
124
+
125
+ foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
126
+ do_action ("ws_plugin__s2member_before_simultaneous_logout", get_defined_vars ());
127
+ unset /* Unset defined __refs, __v. */ ($__refs, $__v);
128
+
129
+ $user = wp_get_current_user();
130
+ $username = $user->user_login; // The username.
131
+ c_ws_plugin__s2member_login_checks::update_simultaneous_logins($username, $user, 'decrement');
132
+ }
133
+
134
+ /**
135
+ * Get simultaneous logins for a particular username.
136
+ *
137
+ * @package s2Member\Login_Checks
138
+ * @since 131025
139
+ *
140
+ * @param string $username Expects a username (e.g. a `user_login` value).
141
+ * @return integer Current number of simultaneous logins.
142
+ */
143
+ public static function get_simultaneous_logins($username)
144
+ {
145
+ if(!$username) return 0; // Nothing to get; should not happen.
146
+
147
+ foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
148
+ do_action ("ws_plugin__s2member_before_get_simultaneous_logins", get_defined_vars ());
149
+ unset /* Unset defined __refs, __v. */ ($__refs, $__v);
150
+
151
+ $prefix = /* s2Member Transient prefix for all simultaneous login monitoring. */ "s2m_slm_";
152
+ $transient_entries = $prefix.md5("s2member_simultaneous_login_entries_for_".strtolower((string)$username));
153
+
154
+ $timeout = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_simultaneous_logins_timeout"];
155
+ $timeout_ago = strtotime("-".$timeout); // e.g. 30 minutes ago.
156
+
157
+ $entries = (is_array($entries = get_transient($transient_entries))) ? $entries : array();
158
+ foreach /* Auto-expire entries, based on time. */($entries as $_entry => $_time)
159
+ if /* Based on time. */($_time < $timeout_ago) unset($entries[$_entry]);
160
+
161
+ return apply_filters("ws_plugin__s2member_get_simultaneous_logins", count($entries), get_defined_vars());
162
+ }
163
+
164
+ /**
165
+ * Update simultaneous logins for a particular username.
166
+ *
167
+ * @package s2Member\Login_Checks
168
+ * @since 131025
169
+ *
170
+ * @attaches-to ``add_action("wp_login");``
171
+ *
172
+ * @param string $username Expects a username (e.g. a `user_login` value).
173
+ * @param WP_User|null $user When fired against `wp_login` this receives a WP_User object also.
174
+ * @param string $action Default action is to increment the counter. This can be set to `decrement` or NULL to do nothing.
175
+ */
176
+ public static function update_simultaneous_logins($username, $user = NULL, $action = 'increment')
177
+ {
178
+ if(!$username) return; // Nothing to do; should not happen.
179
+
180
+ foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
181
+ do_action ("ws_plugin__s2member_before_update_simultaneous_logins", get_defined_vars ());
182
+ unset /* Unset defined __refs, __v. */ ($__refs, $__v);
183
+
184
+ $prefix = /* s2Member Transient prefix for all simultaneous login monitoring. */ "s2m_slm_";
185
+ $transient_entries = $prefix.md5("s2member_simultaneous_login_entries_for_".strtolower((string)$username));
186
+
187
+ $timeout = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_simultaneous_logins_timeout"];
188
+ $timeout_ago = strtotime("-".$timeout); // e.g. 30 minutes ago.
189
+
190
+ $entries = (is_array($entries = get_transient($transient_entries))) ? $entries : array();
191
+ foreach /* Auto-expire entries, based on time. */($entries as $_entry => $_time)
192
+ if /* Based on time. */($_time < $timeout_ago) unset($entries[$_entry]);
193
+
194
+ $total_entries = count($entries); // May need this below.
195
+
196
+ if($action === 'increment') $entries[] = time(); // New entry.
197
+ else if($action === 'decrement') array_pop($entries); // Remove last entry.
198
+ else if($action === 'timer') // Update time on last entry; or add a new entry.
199
+ $entries[(($total_entries) ? $total_entries - 1 : 0)] = time();
200
+
201
+ set_transient($transient_entries, $entries, strtotime("+".$timeout) - time());
202
+
203
+ foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
204
+ do_action ("ws_plugin__s2member_after_update_simultaneous_logins", get_defined_vars ());
205
+ unset /* Unset defined __refs, __v. */ ($__refs, $__v);
206
+ }
207
+ }
208
+ }
209
+ ?>
includes/classes/login-redirects-r.inc.php CHANGED
@@ -30,21 +30,39 @@ if (!class_exists ("c_ws_plugin__s2member_login_redirects_r"))
30
  /**
31
  * Handles completely empty ``login_redirect`` values.
32
  *
33
- * Some plugins (most notably BuddyPress v1.5) have a nasty habit of sending an empty ``$_REQUEST["redirect_to"]`` input field with login widgets.
34
- * In the case of BuddyPress, it's own Filter against `login_redirect` will deal with empty values. However, since s2Member removes all Filters
35
- * against `login_redirect` (for compatibility), we NEED this simple routine to check empty values, and default them to ``admin_url()``.
36
- *
37
  * @attaches-to ``add_filter("login_redirect");``
38
  *
39
  * @package s2Member\Login_Redirects
40
  * @since 110926
41
  *
42
- * @param str $redirect_to Expects the current ``$redirect_to`` value, passed in by the Filter.
43
- * @return str A non-empty string value. s2Member will NEVER allow this to be completely empty.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  */
45
- public static function _empty_login_redirect_filter ($redirect_to = FALSE)
46
  {
47
- return (empty ($redirect_to)) ? admin_url () : $redirect_to;
 
 
 
 
 
 
 
48
  }
49
  /**
50
  * Removes all other ``login_redirect`` Filters to prevent conflicts with s2Member.
@@ -53,8 +71,6 @@ if (!class_exists ("c_ws_plugin__s2member_login_redirects_r"))
53
  *
54
  * @package s2Member\Login_Redirects
55
  * @since 3.5
56
- *
57
- * @return null
58
  */
59
  public static function remove_login_redirect_filters ()
60
  {
@@ -64,10 +80,10 @@ if (!class_exists ("c_ws_plugin__s2member_login_redirects_r"))
64
  {
65
  remove_all_filters /* Removes all `login_redirect` Filters. */("login_redirect");
66
  add_filter ("login_redirect", "c_ws_plugin__s2member_login_redirects_r::_empty_login_redirect_filter");
 
67
 
68
  do_action ("ws_plugin__s2member_during_remove_login_redirect_filters", get_defined_vars ());
69
  }
70
-
71
  do_action ("ws_plugin__s2member_after_remove_login_redirect_filters", get_defined_vars ());
72
 
73
  return /* Return for uniformity. */;
30
  /**
31
  * Handles completely empty ``login_redirect`` values.
32
  *
 
 
 
 
33
  * @attaches-to ``add_filter("login_redirect");``
34
  *
35
  * @package s2Member\Login_Redirects
36
  * @since 110926
37
  *
38
+ * @param string $redirect_to Expects the current ``$redirect_to`` value, passed in by the Filter.
39
+ * @return string A non-empty string value. s2Member will NEVER allow this to be completely empty.
40
+ */
41
+ public static function _empty_login_redirect_filter ($redirect_to)
42
+ {
43
+ return (!$redirect_to) ? admin_url () : $redirect_to;
44
+ }
45
+ /**
46
+ * Handles HTTP/HTTPS ``login_redirect`` values.
47
+ *
48
+ * @attaches-to ``add_filter("login_redirect");``
49
+ *
50
+ * @package s2Member\Login_Redirects
51
+ * @since 130819
52
+ *
53
+ * @param string $redirect_to Expects the current ``$redirect_to`` value, passed in by the Filter.
54
+ * @return string Updated `redirect_to` value.
55
  */
56
+ public static function _http_login_redirect_filter ($redirect_to)
57
  {
58
+ if($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_always_http"])
59
+ if($redirect_to && is_string ($redirect_to) && strpos($redirect_to, "wp-admin") === FALSE)
60
+ {
61
+ $redirect_to = preg_replace("/^https\:\/\//i", "http://", $redirect_to);
62
+ if(stripos($redirect_to, "http://") !== 0) // Force an absolute URL in this case.
63
+ $redirect_to = home_url($redirect_to, "http");
64
+ }
65
+ return $redirect_to;
66
  }
67
  /**
68
  * Removes all other ``login_redirect`` Filters to prevent conflicts with s2Member.
71
  *
72
  * @package s2Member\Login_Redirects
73
  * @since 3.5
 
 
74
  */
75
  public static function remove_login_redirect_filters ()
76
  {
80
  {
81
  remove_all_filters /* Removes all `login_redirect` Filters. */("login_redirect");
82
  add_filter ("login_redirect", "c_ws_plugin__s2member_login_redirects_r::_empty_login_redirect_filter");
83
+ add_filter ("login_redirect", "c_ws_plugin__s2member_login_redirects_r::_http_login_redirect_filter");
84
 
85
  do_action ("ws_plugin__s2member_during_remove_login_redirect_filters", get_defined_vars ());
86
  }
 
87
  do_action ("ws_plugin__s2member_after_remove_login_redirect_filters", get_defined_vars ());
88
 
89
  return /* Return for uniformity. */;
includes/classes/login-redirects.inc.php CHANGED
@@ -27,31 +27,6 @@ if (!class_exists ("c_ws_plugin__s2member_login_redirects"))
27
  */
28
  class c_ws_plugin__s2member_login_redirects
29
  {
30
-
31
- /**
32
- * Assists in multisite User authentication.
33
- *
34
- * @package s2Member\Login_Redirects
35
- * @since 130405
36
- *
37
- * @attaches-to ``add_filter("wp_authenticate_user");``
38
- *
39
- * @param WP_User|WP_Error Expects either a WP_User or WP_Error object passed in by the Filter.
40
- * @return WP_User|WP_Error WP_User or WP_Error object (if there was a problem).
41
- */
42
- public static function ms_wp_authenticate_user ($user_or_wp_error = FALSE)
43
- {
44
- if(!is_multisite()) return $user_or_wp_error;
45
-
46
- foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
47
- do_action ("ws_plugin__s2member_before_ms_wp_authenticate_user", get_defined_vars ());
48
- unset /* Unset defined __refs, __v. */ ($__refs, $__v);
49
-
50
- if(is_a($user_or_wp_error, "WP_User") && ($user = $user_or_wp_error) && $user->ID && !is_super_admin($user->ID) && !in_array(get_current_blog_id(), array_keys(get_blogs_of_user($user->ID)), TRUE))
51
- $user_or_wp_error = new WP_Error("invalid_username", _x("<strong>ERROR</strong>: Invalid username for this site.", "s2member-front", "s2member"));
52
-
53
- return apply_filters ("ws_plugin__s2member_ms_wp_authenticate_user", $user_or_wp_error, get_defined_vars ());
54
- }
55
  /**
56
  * Handles login redirections.
57
  *
@@ -88,6 +63,13 @@ if (!class_exists ("c_ws_plugin__s2member_login_redirects"))
88
  if (($ok = true) && !is_super_admin ($user_id) && $username !== "demo" && !$disable_login_ip_restrictions)
89
  $ok = c_ws_plugin__s2member_ip_restrictions::ip_restrictions_ok ($_SERVER["REMOTE_ADDR"], $username);
90
 
 
 
 
 
 
 
 
91
  if (($redirect = apply_filters ("ws_plugin__s2member_login_redirect", (($user->has_cap ("edit_posts")) ? false : true), get_defined_vars ())))
92
  {
93
  $obey_redirect_to = apply_filters ("ws_plugin__s2member_obey_login_redirect_to", /* By default, we obey this. */ true, get_defined_vars ());
@@ -107,13 +89,15 @@ if (!class_exists ("c_ws_plugin__s2member_login_redirects"))
107
  $redirect = get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"]);
108
 
109
  if($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_always_http"])
110
- $redirect = preg_replace("/^https\:\/\//i", "http://", $redirect);
111
-
 
 
 
112
  wp_redirect($redirect).exit();
113
  }
114
  }
115
  }
116
-
117
  foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
118
  do_action ("ws_plugin__s2member_after_login_redirect", get_defined_vars ());
119
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
27
  */
28
  class c_ws_plugin__s2member_login_redirects
29
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  /**
31
  * Handles login redirections.
32
  *
63
  if (($ok = true) && !is_super_admin ($user_id) && $username !== "demo" && !$disable_login_ip_restrictions)
64
  $ok = c_ws_plugin__s2member_ip_restrictions::ip_restrictions_ok ($_SERVER["REMOTE_ADDR"], $username);
65
 
66
+ if($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_always_http"]) // Alter value of `redirect_to`?
67
+ if(!empty ($_REQUEST["redirect_to"]) && is_string ($_REQUEST["redirect_to"]) && strpos($_REQUEST["redirect_to"], "wp-admin") === FALSE)
68
+ {
69
+ $_REQUEST["redirect_to"] = preg_replace("/^https\:\/\//i", "http://", $_REQUEST["redirect_to"]);
70
+ if(stripos($_REQUEST["redirect_to"], "http://") !== 0) // Force an absolute URL in this case.
71
+ $_REQUEST["redirect_to"] = home_url($_REQUEST["redirect_to"], "http");
72
+ }
73
  if (($redirect = apply_filters ("ws_plugin__s2member_login_redirect", (($user->has_cap ("edit_posts")) ? false : true), get_defined_vars ())))
74
  {
75
  $obey_redirect_to = apply_filters ("ws_plugin__s2member_obey_login_redirect_to", /* By default, we obey this. */ true, get_defined_vars ());
89
  $redirect = get_page_link ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"]);
90
 
91
  if($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_always_http"])
92
+ {
93
+ $redirect = preg_replace("/^https\:\/\//i", "http://", $redirect);
94
+ if(stripos($redirect, "http://") !== 0) // Force an absolute URL in this case.
95
+ $redirect = home_url($redirect, "http");
96
+ }
97
  wp_redirect($redirect).exit();
98
  }
99
  }
100
  }
 
101
  foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
102
  do_action ("ws_plugin__s2member_after_login_redirect", get_defined_vars ());
103
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
includes/classes/menu-pages.inc.php CHANGED
@@ -100,16 +100,16 @@ if(!class_exists("c_ws_plugin__s2member_menu_pages"))
100
  if($options["login_welcome_page"] && $options["login_welcome_page"] === $options["membership_options_page"] && ($display_notices === true || in_array("page-conflict-warnings", (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Login Welcome Page is the same as your Membership Options Page. Please correct this. See: <code>s2Member -› General Options -› Login Welcome Page</code>.'))
101
  ($enqueue_notices === true || in_array("page-conflict-warnings", (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, "*:*", true) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, true);
102
 
103
- if($options["membership_options_page"] && (string)get_option("page_on_front") === $options["membership_options_page"] && ($display_notices === true || in_array("page-conflict-warnings", (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Membership Options Page is currently configured as your Home Page (i.e. static page) for WordPress®. This causes internal conflicts with s2Member. Your Membership Options Page MUST stand alone. Please correct this. See: <code>WordPress® -› Reading Options</code>. Or change: <code>s2Member -› General Options -› Membership Options Page</code>.'))
104
  ($enqueue_notices === true || in_array("page-conflict-warnings", (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, "*:*", true) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, true);
105
 
106
- if($options["login_welcome_page"] && (string)get_option("page_on_front") === $options["login_welcome_page"] && ($display_notices === true || in_array("page-conflict-warnings", (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Login Welcome Page is currently configured as your Home Page (i.e. static page) for WordPress®. This causes internal conflicts with s2Member. Your Login Welcome Page MUST stand alone. Please correct this. See: <code>WordPress® -› Reading Options</code>. Or change: <code>s2Member -› General Options -› Login Welcome Page</code>.'))
107
  ($enqueue_notices === true || in_array("page-conflict-warnings", (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, "*:*", true) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, true);
108
 
109
- if($options["membership_options_page"] && (string)get_option("page_for_posts") === $options["membership_options_page"] && ($display_notices === true || in_array("page-conflict-warnings", (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Membership Options Page is currently configured as your Posts Page (i.e. static page) for WordPress®. This causes internal conflicts with s2Member. Your Membership Options Page MUST stand alone. Please correct this. See: <code>WordPress® -› Reading Options</code>. Or change: <code>s2Member -› General Options -› Membership Options Page</code>.'))
110
  ($enqueue_notices === true || in_array("page-conflict-warnings", (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, "*:*", true) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, true);
111
 
112
- if($options["login_welcome_page"] && (string)get_option("page_for_posts") === $options["login_welcome_page"] && ($display_notices === true || in_array("page-conflict-warnings", (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Login Welcome Page is currently configured as your Posts Page (i.e. static page) for WordPress®. This causes internal conflicts with s2Member. Your Login Welcome Page MUST stand alone. Please correct this. See: <code>WordPress® -› Reading Options</code>. Or change: <code>s2Member -› General Options -› Login Welcome Page</code>.'))
113
  ($enqueue_notices === true || in_array("page-conflict-warnings", (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, "*:*", true) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, true);
114
 
115
  if($options["file_download_limit_exceeded_page"] && $options["file_download_limit_exceeded_page"] === $options["membership_options_page"] && ($display_notices === true || in_array("page-conflict-warnings", (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Download Limit Exceeded Page is the same as your Membership Options Page. Please correct this. See: <code>s2Member -› Download Options</code>.'))
@@ -148,76 +148,67 @@ if(!class_exists("c_ws_plugin__s2member_menu_pages"))
148
  $menu = apply_filters("ws_plugin__s2member_during_add_admin_options_menu_slug", "ws-plugin--s2member-start", get_defined_vars());
149
 
150
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_menu_page", true, get_defined_vars()))
151
- add_menu_page("s2Member®", "s2Member®", "create_users", $menu, "c_ws_plugin__s2member_menu_pages::start_page", $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]."/images/brand-favicon.png");
152
 
153
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_start_page", true, get_defined_vars()))
154
- add_submenu_page($menu, "s2Member® Quick-Start Guide", "Quick-Start Guide", "create_users", "ws-plugin--s2member-start", "c_ws_plugin__s2member_menu_pages::start_page");
155
 
156
  if /* Divider. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_divider_1", true, get_defined_vars()))
157
  add_submenu_page($menu, "", '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', "create_users", "#");
158
 
159
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_mms_ops_page", (!is_multisite() || is_main_site()), get_defined_vars()))
160
- add_submenu_page($menu, "s2Member® Multisite Configuration", "Multisite (Config)", "create_users", "ws-plugin--s2member-mms-ops", "c_ws_plugin__s2member_menu_pages::mms_ops_page");
161
 
162
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_gen_ops_page", true, get_defined_vars()))
163
- add_submenu_page($menu, "s2Member® General Options", "General Options", "create_users", "ws-plugin--s2member-gen-ops", "c_ws_plugin__s2member_menu_pages::gen_ops_page");
164
 
165
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_res_ops_page", true, get_defined_vars()))
166
- add_submenu_page($menu, "s2Member® Restriction Options", "Restriction Options", "create_users", "ws-plugin--s2member-res-ops", "c_ws_plugin__s2member_menu_pages::res_ops_page");
167
 
168
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_down_ops_page", (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()), get_defined_vars()))
169
- add_submenu_page($menu, "s2Member® Download Options", "Download Options", "create_users", "ws-plugin--s2member-down-ops", "c_ws_plugin__s2member_menu_pages::down_ops_page");
170
 
171
  if /* Divider. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_divider_2", true, get_defined_vars()))
172
  add_submenu_page($menu, "", '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', "create_users", "#");
173
 
174
- if /* Shortcut. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_new_user_page", true, get_defined_vars()))
175
- add_submenu_page($menu, "s2Member® / Add A Member", "Add A Member", "create_users", "user-new.php");
176
-
177
- if /* Shortcut. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_browse_users_page", true, get_defined_vars()))
178
- add_submenu_page($menu, "s2Member® / Browse Members", "Browse Members", "create_users", "users.php");
179
-
180
- if /* Divider. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_divider_3", true, get_defined_vars()))
181
- add_submenu_page($menu, "", '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', "create_users", "#");
182
-
183
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_paypal_ops_page", true, get_defined_vars()))
184
- add_submenu_page($menu, "s2Member® PayPal Options", "PayPal® Options", "create_users", "ws-plugin--s2member-paypal-ops", "c_ws_plugin__s2member_menu_pages::paypal_ops_page");
185
 
186
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_paypal_buttons_page", true, get_defined_vars()))
187
- add_submenu_page($menu, "s2Member® PayPal® Buttons", "PayPal® Buttons", "create_users", "ws-plugin--s2member-paypal-buttons", "c_ws_plugin__s2member_menu_pages::paypal_buttons_page");
188
 
189
- if /* Divider. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_divider_4", true, get_defined_vars()))
190
  add_submenu_page($menu, "", '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', "create_users", "#");
191
 
192
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_trk_ops_page", true, get_defined_vars()))
193
- add_submenu_page($menu, "s2Member® API / Tracking", "API / Tracking", "create_users", "ws-plugin--s2member-trk-ops", "c_ws_plugin__s2member_menu_pages::trk_ops_page");
194
 
195
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_els_ops_page", true, get_defined_vars()))
196
- add_submenu_page($menu, "s2Member® API / List Servers", "API / List Servers", "create_users", "ws-plugin--s2member-els-ops", "c_ws_plugin__s2member_menu_pages::els_ops_page");
197
 
198
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_api_ops_page", true, get_defined_vars()))
199
- add_submenu_page($menu, "s2Member® API / Notifications", "API / Notifications", "create_users", "ws-plugin--s2member-api-ops", "c_ws_plugin__s2member_menu_pages::api_ops_page");
200
 
201
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_scripting_page", true, get_defined_vars()))
202
- add_submenu_page($menu, "s2Member® API / Scripting", "API / Scripting", "create_users", "ws-plugin--s2member-scripting", "c_ws_plugin__s2member_menu_pages::scripting_page");
203
 
204
- if /* Divider. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_divider_5", true, get_defined_vars()))
205
  add_submenu_page($menu, "", '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', "create_users", "#");
206
 
207
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_integrations_page", (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()), get_defined_vars()))
208
- add_submenu_page($menu, "s2Member® / Other Integrations", "Other Integrations", "create_users", "ws-plugin--s2member-integrations", "c_ws_plugin__s2member_menu_pages::integrations_page");
209
 
210
- if /* Divider. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_divider_6", true, get_defined_vars()))
211
  add_submenu_page($menu, "", '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', "create_users", "#");
212
 
213
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_logs_page", (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()), get_defined_vars()))
214
- add_submenu_page($menu, "s2Member® Logs", "Log Files (Debug)", "create_users", "ws-plugin--s2member-logs", "c_ws_plugin__s2member_menu_pages::logs_page");
215
 
216
- if /* Divider. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_divider_7", (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()), get_defined_vars()))
217
  add_submenu_page($menu, "", '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', "create_users", "#");
218
 
219
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_info_page", (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()), get_defined_vars()))
220
- add_submenu_page($menu, "s2Member® Information", "s2Member® Info", "create_users", "ws-plugin--s2member-info", "c_ws_plugin__s2member_menu_pages::info_page");
221
 
222
  do_action("ws_plugin__s2member_during_add_admin_options_additional_pages", get_defined_vars());
223
  }
@@ -247,7 +238,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_pages"))
247
 
248
  $menu = /* Used below for nesting additional sub-menu pages. */ "ws-plugin--s2member-mms-ops";
249
 
250
- add_menu_page("s2Member®", "s2Member®", "create_users", $menu, "c_ws_plugin__s2member_menu_pages::mms_ops_page", $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]."/images/brand-favicon.png");
251
 
252
  add_submenu_page($menu, "s2Member Multisite (Configuration)", "Multisite (Config)", "create_users", "ws-plugin--s2member-mms-ops", "c_ws_plugin__s2member_menu_pages::mms_ops_page");
253
 
@@ -675,7 +666,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_pages"))
675
  $htaccess = $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"]."/.htaccess";
676
  $htaccess_contents = trim(c_ws_plugin__s2member_utilities::evl(file_get_contents($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir_htaccess"])));
677
 
678
- $no_gzip_htaccess = /* Always located in the absolute root path for WordPress®. */ ABSPATH.".htaccess";
679
  $no_gzip_htaccess_contents = trim(c_ws_plugin__s2member_utilities::evl(file_get_contents($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_no_gzip_htaccess"])));
680
 
681
  if(!c_ws_plugin__s2member_files::no_gzip_rules_in_root_htaccess() /* If s2Member's GZIP exclusions do NOT yet exist in the root `.htaccess` file. */)
@@ -701,15 +692,15 @@ if(!class_exists("c_ws_plugin__s2member_menu_pages"))
701
 
702
  if(!empty($_POST["ws_plugin__s2member_amazon_cf_files_auto_configure_distros"]) && ($nonce = $_POST["ws_plugin__s2member_amazon_cf_files_auto_configure_distros"]) && wp_verify_nonce($nonce, "ws-plugin--s2member-amazon-cf-files-auto-configure-distros"))
703
  if(($amazon_cf_auto_configure_distros = c_ws_plugin__s2member_files_in::amazon_cf_auto_configure_distros()) && $amazon_cf_auto_configure_distros["success"])
704
- c_ws_plugin__s2member_admin_notices::display_admin_notice('Amazon® CloudFront Distributions auto-configured successfully. Please allow 30 minutes for propagation.'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_downloads_cname"]) ? '<br /><em>Downloads Distribution CNAME: <code>'.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_downloads_cname"]).' &mdash;&raquo; '.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_downloads_dname"]).'</code></em>' : '').(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_streaming_cname"]) ? '<br /><em>Streaming Distribution CNAME: <code>'.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_streaming_cname"]).' &mdash;&raquo; '.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_streaming_dname"]).'</code></em>' : ''));
705
  else // Else there was an error. We need to report this back to the site owner so they can understand what's going on.
706
- (c_ws_plugin__s2member_menu_pages::$pre_display_errors["cf_files_auto_configure_distros"] = true).c_ws_plugin__s2member_admin_notices::display_admin_notice('Unable to auto-configure Amazon® CloudFront Distributions.<br />Error code: <code>'.esc_html($amazon_cf_auto_configure_distros["code"]).'</code>. Error Message: <code>'.esc_html($amazon_cf_auto_configure_distros["message"]).'</code>', true);
707
 
708
  if(!empty($_POST["ws_plugin__s2member_amazon_s3_files_auto_configure_acls"]) && ($nonce = $_POST["ws_plugin__s2member_amazon_s3_files_auto_configure_acls"]) && wp_verify_nonce($nonce, "ws-plugin--s2member-amazon-s3-files-auto-configure-acls"))
709
  if(($amazon_s3_auto_configure_acls = c_ws_plugin__s2member_files_in::amazon_s3_auto_configure_acls()) && $amazon_s3_auto_configure_acls["success"])
710
- c_ws_plugin__s2member_admin_notices::display_admin_notice('Amazon® S3 ACLs auto-configured successfully.');
711
  else // Else there was an error. We need to report this back to the site owner so they can understand what's going on.
712
- (c_ws_plugin__s2member_menu_pages::$pre_display_errors["s3_files_auto_configure_acls"] = true).c_ws_plugin__s2member_admin_notices::display_admin_notice('Unable to auto-configure Amazon® S3 ACLs.<br />Error code: <code>'.esc_html($amazon_s3_auto_configure_acls["code"]).'</code>. Error Message: <code>'.esc_html($amazon_s3_auto_configure_acls["message"]).'</code>', true);
713
 
714
  include_once dirname(dirname(__FILE__))."/menu-pages/down-ops.inc.php";
715
 
@@ -790,7 +781,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_pages"))
790
  do_action("ws_plugin__s2member_before_paypal_buttons_page", get_defined_vars());
791
 
792
  if(!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"] || !$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_username"] || !$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_password"] || !$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_signature"])
793
- c_ws_plugin__s2member_admin_notices::display_admin_notice('Please configure <code>s2Member -› PayPal® Options</code> first. Once all of your PayPal® Options are configured; including your Email Address, API Username, Password, and Signature; return to this page &amp; generate your PayPal® Button(s).', true);
794
 
795
  include_once dirname(dirname(__FILE__))."/menu-pages/paypal-buttons.inc.php";
796
 
100
  if($options["login_welcome_page"] && $options["login_welcome_page"] === $options["membership_options_page"] && ($display_notices === true || in_array("page-conflict-warnings", (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Login Welcome Page is the same as your Membership Options Page. Please correct this. See: <code>s2Member -› General Options -› Login Welcome Page</code>.'))
101
  ($enqueue_notices === true || in_array("page-conflict-warnings", (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, "*:*", true) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, true);
102
 
103
+ if($options["membership_options_page"] && (string)get_option("page_on_front") === $options["membership_options_page"] && ($display_notices === true || in_array("page-conflict-warnings", (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Membership Options Page is currently configured as your Home Page (i.e. static page) for WordPress. This causes internal conflicts with s2Member. Your Membership Options Page MUST stand alone. Please correct this. See: <code>WordPress -› Reading Options</code>. Or change: <code>s2Member -› General Options -› Membership Options Page</code>.'))
104
  ($enqueue_notices === true || in_array("page-conflict-warnings", (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, "*:*", true) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, true);
105
 
106
+ if($options["login_welcome_page"] && (string)get_option("page_on_front") === $options["login_welcome_page"] && ($display_notices === true || in_array("page-conflict-warnings", (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Login Welcome Page is currently configured as your Home Page (i.e. static page) for WordPress. This causes internal conflicts with s2Member. Your Login Welcome Page MUST stand alone. Please correct this. See: <code>WordPress -› Reading Options</code>. Or change: <code>s2Member -› General Options -› Login Welcome Page</code>.'))
107
  ($enqueue_notices === true || in_array("page-conflict-warnings", (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, "*:*", true) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, true);
108
 
109
+ if($options["membership_options_page"] && (string)get_option("page_for_posts") === $options["membership_options_page"] && ($display_notices === true || in_array("page-conflict-warnings", (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Membership Options Page is currently configured as your Posts Page (i.e. static page) for WordPress. This causes internal conflicts with s2Member. Your Membership Options Page MUST stand alone. Please correct this. See: <code>WordPress -› Reading Options</code>. Or change: <code>s2Member -› General Options -› Membership Options Page</code>.'))
110
  ($enqueue_notices === true || in_array("page-conflict-warnings", (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, "*:*", true) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, true);
111
 
112
+ if($options["login_welcome_page"] && (string)get_option("page_for_posts") === $options["login_welcome_page"] && ($display_notices === true || in_array("page-conflict-warnings", (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Login Welcome Page is currently configured as your Posts Page (i.e. static page) for WordPress. This causes internal conflicts with s2Member. Your Login Welcome Page MUST stand alone. Please correct this. See: <code>WordPress -› Reading Options</code>. Or change: <code>s2Member -› General Options -› Login Welcome Page</code>.'))
113
  ($enqueue_notices === true || in_array("page-conflict-warnings", (array)$enqueue_notices)) ? c_ws_plugin__s2member_admin_notices::enqueue_admin_notice($notice, "*:*", true) : c_ws_plugin__s2member_admin_notices::display_admin_notice($notice, true);
114
 
115
  if($options["file_download_limit_exceeded_page"] && $options["file_download_limit_exceeded_page"] === $options["membership_options_page"] && ($display_notices === true || in_array("page-conflict-warnings", (array)$display_notices)) && ($notice = '<strong>s2Member:</strong> Your Download Limit Exceeded Page is the same as your Membership Options Page. Please correct this. See: <code>s2Member -› Download Options</code>.'))
148
  $menu = apply_filters("ws_plugin__s2member_during_add_admin_options_menu_slug", "ws-plugin--s2member-start", get_defined_vars());
149
 
150
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_menu_page", true, get_defined_vars()))
151
+ add_menu_page("s2Member", "s2Member", "create_users", $menu, "c_ws_plugin__s2member_menu_pages::start_page", $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]."/images/brand-favicon.png");
152
 
153
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_start_page", true, get_defined_vars()))
154
+ add_submenu_page($menu, "s2Member Quick-Start Guide", "Quick-Start Guide", "create_users", "ws-plugin--s2member-start", "c_ws_plugin__s2member_menu_pages::start_page");
155
 
156
  if /* Divider. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_divider_1", true, get_defined_vars()))
157
  add_submenu_page($menu, "", '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', "create_users", "#");
158
 
159
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_mms_ops_page", (!is_multisite() || is_main_site()), get_defined_vars()))
160
+ add_submenu_page($menu, "s2Member Multisite Configuration", "Multisite (Config)", "create_users", "ws-plugin--s2member-mms-ops", "c_ws_plugin__s2member_menu_pages::mms_ops_page");
161
 
162
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_gen_ops_page", true, get_defined_vars()))
163
+ add_submenu_page($menu, "s2Member General Options", "General Options", "create_users", "ws-plugin--s2member-gen-ops", "c_ws_plugin__s2member_menu_pages::gen_ops_page");
164
 
165
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_res_ops_page", true, get_defined_vars()))
166
+ add_submenu_page($menu, "s2Member Restriction Options", "Restriction Options", "create_users", "ws-plugin--s2member-res-ops", "c_ws_plugin__s2member_menu_pages::res_ops_page");
167
 
168
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_down_ops_page", (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()), get_defined_vars()))
169
+ add_submenu_page($menu, "s2Member Download Options", "Download Options", "create_users", "ws-plugin--s2member-down-ops", "c_ws_plugin__s2member_menu_pages::down_ops_page");
170
 
171
  if /* Divider. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_divider_2", true, get_defined_vars()))
172
  add_submenu_page($menu, "", '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', "create_users", "#");
173
 
 
 
 
 
 
 
 
 
 
174
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_paypal_ops_page", true, get_defined_vars()))
175
+ add_submenu_page($menu, "s2Member PayPal Options", "PayPal Options", "create_users", "ws-plugin--s2member-paypal-ops", "c_ws_plugin__s2member_menu_pages::paypal_ops_page");
176
 
177
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_paypal_buttons_page", true, get_defined_vars()))
178
+ add_submenu_page($menu, "s2Member PayPal Buttons", "PayPal Buttons", "create_users", "ws-plugin--s2member-paypal-buttons", "c_ws_plugin__s2member_menu_pages::paypal_buttons_page");
179
 
180
+ if /* Divider. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_divider_3", true, get_defined_vars()))
181
  add_submenu_page($menu, "", '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', "create_users", "#");
182
 
183
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_trk_ops_page", true, get_defined_vars()))
184
+ add_submenu_page($menu, "s2Member API / Tracking", "API / Tracking", "create_users", "ws-plugin--s2member-trk-ops", "c_ws_plugin__s2member_menu_pages::trk_ops_page");
185
 
186
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_els_ops_page", true, get_defined_vars()))
187
+ add_submenu_page($menu, "s2Member API / List Servers", "API / List Servers", "create_users", "ws-plugin--s2member-els-ops", "c_ws_plugin__s2member_menu_pages::els_ops_page");
188
 
189
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_api_ops_page", true, get_defined_vars()))
190
+ add_submenu_page($menu, "s2Member API / Notifications", "API / Notifications", "create_users", "ws-plugin--s2member-api-ops", "c_ws_plugin__s2member_menu_pages::api_ops_page");
191
 
192
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_scripting_page", true, get_defined_vars()))
193
+ add_submenu_page($menu, "s2Member API / Scripting", "API / Scripting", "create_users", "ws-plugin--s2member-scripting", "c_ws_plugin__s2member_menu_pages::scripting_page");
194
 
195
+ if /* Divider. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_divider_4", true, get_defined_vars()))
196
  add_submenu_page($menu, "", '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', "create_users", "#");
197
 
198
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_integrations_page", (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()), get_defined_vars()))
199
+ add_submenu_page($menu, "s2Member / Other Integrations", "Other Integrations", "create_users", "ws-plugin--s2member-integrations", "c_ws_plugin__s2member_menu_pages::integrations_page");
200
 
201
+ if /* Divider. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_divider_5", true, get_defined_vars()))
202
  add_submenu_page($menu, "", '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', "create_users", "#");
203
 
204
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_logs_page", (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()), get_defined_vars()))
205
+ add_submenu_page($menu, "s2Member Logs", "Log Files (Debug)", "create_users", "ws-plugin--s2member-logs", "c_ws_plugin__s2member_menu_pages::logs_page");
206
 
207
+ if /* Divider. */(apply_filters("ws_plugin__s2member_during_add_admin_options_add_divider_6", (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()), get_defined_vars()))
208
  add_submenu_page($menu, "", '<span style="display:block; margin:1px 0 1px -5px; padding:0; height:1px; line-height:1px; background:#CCCCCC;"></span>', "create_users", "#");
209
 
210
  if(apply_filters("ws_plugin__s2member_during_add_admin_options_add_info_page", (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()), get_defined_vars()))
211
+ add_submenu_page($menu, "s2Member Information", "s2Member Info", "create_users", "ws-plugin--s2member-info", "c_ws_plugin__s2member_menu_pages::info_page");
212
 
213
  do_action("ws_plugin__s2member_during_add_admin_options_additional_pages", get_defined_vars());
214
  }
238
 
239
  $menu = /* Used below for nesting additional sub-menu pages. */ "ws-plugin--s2member-mms-ops";
240
 
241
+ add_menu_page("s2Member", "s2Member", "create_users", $menu, "c_ws_plugin__s2member_menu_pages::mms_ops_page", $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]."/images/brand-favicon.png");
242
 
243
  add_submenu_page($menu, "s2Member Multisite (Configuration)", "Multisite (Config)", "create_users", "ws-plugin--s2member-mms-ops", "c_ws_plugin__s2member_menu_pages::mms_ops_page");
244
 
666
  $htaccess = $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"]."/.htaccess";
667
  $htaccess_contents = trim(c_ws_plugin__s2member_utilities::evl(file_get_contents($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir_htaccess"])));
668
 
669
+ $no_gzip_htaccess = /* Always located in the absolute root path for WordPress. */ ABSPATH.".htaccess";
670
  $no_gzip_htaccess_contents = trim(c_ws_plugin__s2member_utilities::evl(file_get_contents($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_no_gzip_htaccess"])));
671
 
672
  if(!c_ws_plugin__s2member_files::no_gzip_rules_in_root_htaccess() /* If s2Member's GZIP exclusions do NOT yet exist in the root `.htaccess` file. */)
692
 
693
  if(!empty($_POST["ws_plugin__s2member_amazon_cf_files_auto_configure_distros"]) && ($nonce = $_POST["ws_plugin__s2member_amazon_cf_files_auto_configure_distros"]) && wp_verify_nonce($nonce, "ws-plugin--s2member-amazon-cf-files-auto-configure-distros"))
694
  if(($amazon_cf_auto_configure_distros = c_ws_plugin__s2member_files_in::amazon_cf_auto_configure_distros()) && $amazon_cf_auto_configure_distros["success"])
695
+ c_ws_plugin__s2member_admin_notices::display_admin_notice('Amazon CloudFront Distributions auto-configured successfully. Please allow 30 minutes for propagation.'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_downloads_cname"]) ? '<br /><em>Downloads Distribution CNAME: <code>'.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_downloads_cname"]).' &mdash;&raquo; '.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_downloads_dname"]).'</code></em>' : '').(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_streaming_cname"]) ? '<br /><em>Streaming Distribution CNAME: <code>'.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_streaming_cname"]).' &mdash;&raquo; '.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_streaming_dname"]).'</code></em>' : ''));
696
  else // Else there was an error. We need to report this back to the site owner so they can understand what's going on.
697
+ (c_ws_plugin__s2member_menu_pages::$pre_display_errors["cf_files_auto_configure_distros"] = true).c_ws_plugin__s2member_admin_notices::display_admin_notice('Unable to auto-configure Amazon CloudFront Distributions.<br />Error code: <code>'.esc_html($amazon_cf_auto_configure_distros["code"]).'</code>. Error Message: <code>'.esc_html($amazon_cf_auto_configure_distros["message"]).'</code>', true);
698
 
699
  if(!empty($_POST["ws_plugin__s2member_amazon_s3_files_auto_configure_acls"]) && ($nonce = $_POST["ws_plugin__s2member_amazon_s3_files_auto_configure_acls"]) && wp_verify_nonce($nonce, "ws-plugin--s2member-amazon-s3-files-auto-configure-acls"))
700
  if(($amazon_s3_auto_configure_acls = c_ws_plugin__s2member_files_in::amazon_s3_auto_configure_acls()) && $amazon_s3_auto_configure_acls["success"])
701
+ c_ws_plugin__s2member_admin_notices::display_admin_notice('Amazon S3 ACLs auto-configured successfully.');
702
  else // Else there was an error. We need to report this back to the site owner so they can understand what's going on.
703
+ (c_ws_plugin__s2member_menu_pages::$pre_display_errors["s3_files_auto_configure_acls"] = true).c_ws_plugin__s2member_admin_notices::display_admin_notice('Unable to auto-configure Amazon S3 ACLs.<br />Error code: <code>'.esc_html($amazon_s3_auto_configure_acls["code"]).'</code>. Error Message: <code>'.esc_html($amazon_s3_auto_configure_acls["message"]).'</code>', true);
704
 
705
  include_once dirname(dirname(__FILE__))."/menu-pages/down-ops.inc.php";
706
 
781
  do_action("ws_plugin__s2member_before_paypal_buttons_page", get_defined_vars());
782
 
783
  if(!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"] || !$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_username"] || !$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_password"] || !$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_signature"])
784
+ c_ws_plugin__s2member_admin_notices::display_admin_notice('Please configure <code>s2Member -› PayPal Options</code> first. Once all of your PayPal Options are configured; including your Email Address, API Username, Password, and Signature; return to this page &amp; generate your PayPal Button(s).', true);
785
 
786
  include_once dirname(dirname(__FILE__))."/menu-pages/paypal-buttons.inc.php";
787
 
includes/classes/meta-box-saves.inc.php CHANGED
@@ -67,7 +67,7 @@ if (!class_exists ("c_ws_plugin__s2member_meta_box_saves"))
67
  unset($pages[$n][$i]);
68
 
69
  if (isset ($pages[$_p["ws_plugin__s2member_security_meta_box_level"]]) && is_array ($pages[$_p["ws_plugin__s2member_security_meta_box_level"]]))
70
- if ($pages[$_p["ws_plugin__s2member_security_meta_box_level"]] !== array ("all")&& !in_array ("all-pages", $posts[$_p["ws_plugin__s2member_security_meta_box_level"]]))
71
  array_push ($pages[$_p["ws_plugin__s2member_security_meta_box_level"]], (string)$page_id);
72
 
73
  for ($n = 0, $new_options = array (); $n <= $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]; $n++)
@@ -93,7 +93,7 @@ if (!class_exists ("c_ws_plugin__s2member_meta_box_saves"))
93
  unset($posts[$n][$i]);
94
 
95
  if (isset ($posts[$_p["ws_plugin__s2member_security_meta_box_level"]]) && is_array ($posts[$_p["ws_plugin__s2member_security_meta_box_level"]]))
96
- if ($posts[$_p["ws_plugin__s2member_security_meta_box_level"]] !== array ("all")&& !in_array ("all-" . $_p["post_type"] . "s", $posts[$_p["ws_plugin__s2member_security_meta_box_level"]]))
97
  array_push ($posts[$_p["ws_plugin__s2member_security_meta_box_level"]], (string)$post_id);
98
 
99
  for ($n = 0, $new_options = array (); $n <= $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]; $n++)
67
  unset($pages[$n][$i]);
68
 
69
  if (isset ($pages[$_p["ws_plugin__s2member_security_meta_box_level"]]) && is_array ($pages[$_p["ws_plugin__s2member_security_meta_box_level"]]))
70
+ if ($pages[$_p["ws_plugin__s2member_security_meta_box_level"]] !== array ("all") && !in_array ("all-page", $posts[$_p["ws_plugin__s2member_security_meta_box_level"]]) && !in_array ("all-pages", $posts[$_p["ws_plugin__s2member_security_meta_box_level"]]))
71
  array_push ($pages[$_p["ws_plugin__s2member_security_meta_box_level"]], (string)$page_id);
72
 
73
  for ($n = 0, $new_options = array (); $n <= $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]; $n++)
93
  unset($posts[$n][$i]);
94
 
95
  if (isset ($posts[$_p["ws_plugin__s2member_security_meta_box_level"]]) && is_array ($posts[$_p["ws_plugin__s2member_security_meta_box_level"]]))
96
+ if ($posts[$_p["ws_plugin__s2member_security_meta_box_level"]] !== array ("all") && !in_array ("all-" . $_p["post_type"], $posts[$_p["ws_plugin__s2member_security_meta_box_level"]]) && !in_array ("all-" . $_p["post_type"] . "s", $posts[$_p["ws_plugin__s2member_security_meta_box_level"]]))
97
  array_push ($posts[$_p["ws_plugin__s2member_security_meta_box_level"]], (string)$post_id);
98
 
99
  for ($n = 0, $new_options = array (); $n <= $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]; $n++)
includes/classes/meta-box-security.inc.php CHANGED
@@ -64,7 +64,7 @@ if(!class_exists("c_ws_plugin__s2member_meta_box_security"))
64
 
65
  for($n = 0; $n <= $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]; $n++)
66
  echo ($pages[$n] !== array("all")) ? // Protecting `all` Pages, of any kind?
67
- ((!in_array("all-pages", $posts[$n])) // Protecting Posts of type: `page` ( i.e. `all-pages` )?
68
  ? '<option value="'.$n.'"'.((in_array($page_id, $pages[$n])) ? ' selected="selected"' : '').'>'.(($n === $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]) ? 'Require Highest Level #'.$n : 'Require Level #'.$n.' (or higher)').'</option>'."\n"
69
  : '<option value="" disabled="disabled">Level #'.$n.' (already protects "all" Posts of this type)</option>'."\n")
70
  : '<option value="" disabled="disabled">Level #'.$n.' (already protects "all" Pages)</option>'."\n";
@@ -110,7 +110,7 @@ if(!class_exists("c_ws_plugin__s2member_meta_box_security"))
110
 
111
  for($n = 0; $n <= $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]; $n++)
112
  echo ($posts[$n] !== array("all")) ? // Protecting `all` Posts, of any kind?
113
- ((!in_array("all-".$post->post_type."s", $posts[$n])) // Protecting Posts `all-[of-this-type]` ( don't forget plural `s` )?
114
  ? '<option value="'.$n.'"'.((in_array($post_id, $posts[$n])) ? ' selected="selected"' : '').'>'.(($n === $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]) ? 'Require Highest Level #'.$n : 'Require Level #'.$n.' (or higher)').'</option>'."\n"
115
  : '<option value="" disabled="disabled">Level #'.$n.' (already protects "all" Posts of this type)</option>'."\n")
116
  : '<option value="" disabled="disabled">Level #'.$n.' (already protects "all" Posts)</option>'."\n";
64
 
65
  for($n = 0; $n <= $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]; $n++)
66
  echo ($pages[$n] !== array("all")) ? // Protecting `all` Pages, of any kind?
67
+ ((!in_array("all-page", $posts[$n]) && !in_array("all-pages", $posts[$n])) // Protecting Posts of type: `page`?
68
  ? '<option value="'.$n.'"'.((in_array($page_id, $pages[$n])) ? ' selected="selected"' : '').'>'.(($n === $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]) ? 'Require Highest Level #'.$n : 'Require Level #'.$n.' (or higher)').'</option>'."\n"
69
  : '<option value="" disabled="disabled">Level #'.$n.' (already protects "all" Posts of this type)</option>'."\n")
70
  : '<option value="" disabled="disabled">Level #'.$n.' (already protects "all" Pages)</option>'."\n";
110
 
111
  for($n = 0; $n <= $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]; $n++)
112
  echo ($posts[$n] !== array("all")) ? // Protecting `all` Posts, of any kind?
113
+ ((!in_array("all-".$post->post_type, $posts[$n]) && !in_array("all-".$post->post_type."s", $posts[$n])) // Protecting Posts `all-[of-this-type]`?
114
  ? '<option value="'.$n.'"'.((in_array($post_id, $posts[$n])) ? ' selected="selected"' : '').'>'.(($n === $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]) ? 'Require Highest Level #'.$n : 'Require Level #'.$n.' (or higher)').'</option>'."\n"
115
  : '<option value="" disabled="disabled">Level #'.$n.' (already protects "all" Posts of this type)</option>'."\n")
116
  : '<option value="" disabled="disabled">Level #'.$n.' (already protects "all" Posts)</option>'."\n";
includes/classes/meta-boxes.inc.php CHANGED
@@ -30,7 +30,7 @@ if (!class_exists ("c_ws_plugin__s2member_meta_boxes"))
30
  /**
31
  * Adds meta boxes to Post/Page editing stations.
32
  *
33
- * Note: WordPress® also calls this Hook with ``$type`` set to: `link` and `comment`. Possibly others.
34
  * Thus, the need for: ``in_array ($type, array_keys (get_post_types ()))``.
35
  *
36
  * @package s2Member\Meta_Boxes
@@ -49,7 +49,7 @@ if (!class_exists ("c_ws_plugin__s2member_meta_boxes"))
49
  $excluded_types = apply_filters ("ws_plugin__s2member_add_meta_boxes_excluded_types", $excluded_types, get_defined_vars ());
50
 
51
  if (in_array ($type, array_keys (get_post_types ())) && !in_array ($type, $excluded_types))
52
- add_meta_box ("ws-plugin--s2member-security", "s2Member®", "c_ws_plugin__s2member_meta_box_security::security_meta_box", $type, "side", "high");
53
 
54
  do_action ("ws_plugin__s2member_after_add_meta_boxes", get_defined_vars ());
55
 
30
  /**
31
  * Adds meta boxes to Post/Page editing stations.
32
  *
33
+ * Note: WordPress also calls this Hook with ``$type`` set to: `link` and `comment`. Possibly others.
34
  * Thus, the need for: ``in_array ($type, array_keys (get_post_types ()))``.
35
  *
36
  * @package s2Member\Meta_Boxes
49
  $excluded_types = apply_filters ("ws_plugin__s2member_add_meta_boxes_excluded_types", $excluded_types, get_defined_vars ());
50
 
51
  if (in_array ($type, array_keys (get_post_types ())) && !in_array ($type, $excluded_types))
52
+ add_meta_box ("ws-plugin--s2member-security", "s2Member", "c_ws_plugin__s2member_meta_box_security::security_meta_box", $type, "side", "high");
53
 
54
  do_action ("ws_plugin__s2member_after_add_meta_boxes", get_defined_vars ());
55
 
includes/classes/mms-patches.inc.php CHANGED
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_mms_patches"))
28
  class c_ws_plugin__s2member_mms_patches
29
  {
30
  /**
31
- * Synchronizes Multisite patches with WordPress® core upgrades.
32
  *
33
  * @package s2Member\Main_Multisite_Patches
34
  * @since 3.5
@@ -72,7 +72,7 @@ if (!class_exists ("c_ws_plugin__s2member_mms_patches"))
72
  {
73
  do_action ("ws_plugin__s2member_during_mms_patches_before", get_defined_vars ());
74
 
75
- $wp_login_file = ABSPATH . "wp-login.php"; // This works for both WordPress® 3.0 and 3.1. WordPress® 3.1+ uses: `site_url('wp-signup.php')`. WordPress® 3.5+ uses: `network_site_url('wp-signup.php')`.
76
  $wp_login_section = "/([\r\n\t\s ]+)(wp_redirect( *?)\(( *?)apply_filters( *?)\(( *?)['\"]wp_signup_location['\"],( *?)(site_url( *?)\(( *?)['\"]wp-signup\.php['\"]( *?)\)|network_site_url( *?)\(( *?)['\"]wp-signup\.php['\"]( *?)\)|get_bloginfo( *?)\(['\"]wpurl['\"]\)( *?)\.( *?)['\"]\/wp-signup\.php['\"])( *?)\)( *?)\);)([\r\n\t\s ]+)(exit;)/";
77
  $wp_login_replace = "\n\t\t// Modified for full plugin compatiblity.\n\t\t//wp_redirect( apply_filters( 'wp_signup_location', network_site_url('wp-signup.php') ) );\n\t\t//exit;";
78
 
@@ -82,7 +82,7 @@ if (!class_exists ("c_ws_plugin__s2member_mms_patches"))
82
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-login.php</code> file ' . (($wp_login_patched_already) ? 'is patched' : 'has been patched successfully') . '.') : null;
83
  else if (!$wp_login_written) // Otherwise, we need to report that /wp-login.php could NOT be updated. Possibly a permissions error.
84
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-login.php</code> file could NOT be patched. Patch NOT written.', true) : null;
85
- else if (!$wp_login_patched) // Otherwise, we need to report that /wp-login.php could NOT be updated. Wrong WordPress® version?
86
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-login.php</code> file could NOT be patched. Unverifiable.', true) : null;
87
  }
88
  else // Otherwise, we need to report that /wp-login.php could NOT be updated. Possibly a permissions error.
@@ -98,7 +98,7 @@ if (!class_exists ("c_ws_plugin__s2member_mms_patches"))
98
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-includes/load.php</code> file ' . (($load_patched_already) ? 'is patched' : 'has been patched successfully') . '.') : null;
99
  else if (!$load_written) // Otherwise, we need to report that /wp-includes/load.php could NOT be updated. Possibly a permissions error.
100
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-includes/load.php</code> file could NOT be patched. Patch NOT written.', true) : null;
101
- else if (!$load_patched) // Otherwise, we need to report that /wp-includes/load.php could NOT be updated. Wrong WordPress® version?
102
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-includes/load.php</code> file could NOT be patched. Unverifiable.', true) : null;
103
  }
104
  else // Otherwise, we need to report that /wp-includes/load.php could NOT be updated. Possibly a permissions error.
@@ -114,7 +114,7 @@ if (!class_exists ("c_ws_plugin__s2member_mms_patches"))
114
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-admin/user-new.php</code> file ' . (($user_new_patched_already) ? 'is patched' : 'has been patched successfully') . '.') : null;
115
  else if (!$user_new_written) // Otherwise, we need to report that /wp-admin/user-new.php could NOT be updated. Possibly a permissions error.
116
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-admin/user-new.php</code> file could NOT be patched. Patch NOT written.', true) : null;
117
- else if (!$user_new_patched) // Otherwise, we need to report that /wp-admin/user-new.php could NOT be updated. Wrong WordPress® version?
118
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-admin/user-new.php</code> file could NOT be patched. Unverifiable.', true) : null;
119
  }
120
  else // Otherwise, we need to report that /wp-admin/user-new.php could NOT be updated. Possibly a permissions error.
@@ -130,7 +130,7 @@ if (!class_exists ("c_ws_plugin__s2member_mms_patches"))
130
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-includes/ms-functions.php</code> file ' . (($ms_functions_patched_already) ? 'is patched' : 'has been patched successfully') . '.') : null;
131
  else if (!$ms_functions_written) // Otherwise, we need to report that /wp-includes/ms-functions.php could NOT be updated. Possibly a permissions error.
132
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-includes/ms-functions.php</code> file could NOT be patched. Patch NOT written.', true) : null;
133
- else if (!$ms_functions_patched) // Otherwise, we need to report that /wp-includes/ms-functions.php could NOT be updated. Wrong WordPress® version?
134
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-includes/ms-functions.php</code> file could NOT be patched. Unverifiable.', true) : null;
135
  }
136
  else // Otherwise, we need to report that /wp-includes/ms-functions.php could NOT be updated. Possibly a permissions error.
28
  class c_ws_plugin__s2member_mms_patches
29
  {
30
  /**
31
+ * Synchronizes Multisite patches with WordPress core upgrades.
32
  *
33
  * @package s2Member\Main_Multisite_Patches
34
  * @since 3.5
72
  {
73
  do_action ("ws_plugin__s2member_during_mms_patches_before", get_defined_vars ());
74
 
75
+ $wp_login_file = ABSPATH . "wp-login.php"; // This works for both WordPress 3.0 and 3.1. WordPress 3.1+ uses: `site_url('wp-signup.php')`. WordPress 3.5+ uses: `network_site_url('wp-signup.php')`.
76
  $wp_login_section = "/([\r\n\t\s ]+)(wp_redirect( *?)\(( *?)apply_filters( *?)\(( *?)['\"]wp_signup_location['\"],( *?)(site_url( *?)\(( *?)['\"]wp-signup\.php['\"]( *?)\)|network_site_url( *?)\(( *?)['\"]wp-signup\.php['\"]( *?)\)|get_bloginfo( *?)\(['\"]wpurl['\"]\)( *?)\.( *?)['\"]\/wp-signup\.php['\"])( *?)\)( *?)\);)([\r\n\t\s ]+)(exit;)/";
77
  $wp_login_replace = "\n\t\t// Modified for full plugin compatiblity.\n\t\t//wp_redirect( apply_filters( 'wp_signup_location', network_site_url('wp-signup.php') ) );\n\t\t//exit;";
78
 
82
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-login.php</code> file ' . (($wp_login_patched_already) ? 'is patched' : 'has been patched successfully') . '.') : null;
83
  else if (!$wp_login_written) // Otherwise, we need to report that /wp-login.php could NOT be updated. Possibly a permissions error.
84
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-login.php</code> file could NOT be patched. Patch NOT written.', true) : null;
85
+ else if (!$wp_login_patched) // Otherwise, we need to report that /wp-login.php could NOT be updated. Wrong WordPress version?
86
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-login.php</code> file could NOT be patched. Unverifiable.', true) : null;
87
  }
88
  else // Otherwise, we need to report that /wp-login.php could NOT be updated. Possibly a permissions error.
98
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-includes/load.php</code> file ' . (($load_patched_already) ? 'is patched' : 'has been patched successfully') . '.') : null;
99
  else if (!$load_written) // Otherwise, we need to report that /wp-includes/load.php could NOT be updated. Possibly a permissions error.
100
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-includes/load.php</code> file could NOT be patched. Patch NOT written.', true) : null;
101
+ else if (!$load_patched) // Otherwise, we need to report that /wp-includes/load.php could NOT be updated. Wrong WordPress version?
102
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-includes/load.php</code> file could NOT be patched. Unverifiable.', true) : null;
103
  }
104
  else // Otherwise, we need to report that /wp-includes/load.php could NOT be updated. Possibly a permissions error.
114
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-admin/user-new.php</code> file ' . (($user_new_patched_already) ? 'is patched' : 'has been patched successfully') . '.') : null;
115
  else if (!$user_new_written) // Otherwise, we need to report that /wp-admin/user-new.php could NOT be updated. Possibly a permissions error.
116
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-admin/user-new.php</code> file could NOT be patched. Patch NOT written.', true) : null;
117
+ else if (!$user_new_patched) // Otherwise, we need to report that /wp-admin/user-new.php could NOT be updated. Wrong WordPress version?
118
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-admin/user-new.php</code> file could NOT be patched. Unverifiable.', true) : null;
119
  }
120
  else // Otherwise, we need to report that /wp-admin/user-new.php could NOT be updated. Possibly a permissions error.
130
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-includes/ms-functions.php</code> file ' . (($ms_functions_patched_already) ? 'is patched' : 'has been patched successfully') . '.') : null;
131
  else if (!$ms_functions_written) // Otherwise, we need to report that /wp-includes/ms-functions.php could NOT be updated. Possibly a permissions error.
132
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-includes/ms-functions.php</code> file could NOT be patched. Patch NOT written.', true) : null;
133
+ else if (!$ms_functions_patched) // Otherwise, we need to report that /wp-includes/ms-functions.php could NOT be updated. Wrong WordPress version?
134
  ($display_notices) ? c_ws_plugin__s2member_admin_notices::display_admin_notice ('Your <code>/wp-includes/ms-functions.php</code> file could NOT be patched. Unverifiable.', true) : null;
135
  }
136
  else // Otherwise, we need to report that /wp-includes/ms-functions.php could NOT be updated. Possibly a permissions error.
includes/classes/no-cache.inc.php CHANGED
@@ -59,7 +59,7 @@ if (!class_exists ("c_ws_plugin__s2member_no_cache"))
59
  return true; // Always return true.
60
  }
61
  /**
62
- * Defines no-cache constants for various WordPress® plugins.
63
  *
64
  * This is compatible with Quick Cache, W3 Total Cache, and also with WP Super Cache.
65
  * Quick Cache uses: ``QUICK_CACHE_ALLOWED``, and other plugins use: ``DONOTCACHEPAGE``.
59
  return true; // Always return true.
60
  }
61
  /**
62
+ * Defines no-cache constants for various WordPress plugins.
63
  *
64
  * This is compatible with Quick Cache, W3 Total Cache, and also with WP Super Cache.
65
  * Quick Cache uses: ``QUICK_CACHE_ALLOWED``, and other plugins use: ``DONOTCACHEPAGE``.
includes/classes/op-notices.inc.php CHANGED
@@ -45,10 +45,10 @@ if (!class_exists ("c_ws_plugin__s2member_op_notices"))
45
 
46
  if (is_blog_admin () && $pagenow === "options-general.php" && !isset ($_GET["page"]) && !is_multisite ()) // Multisite does NOT provide these options.
47
  {
48
- $notice = "<em>* Note: The s2Member plugin has control over two options on this page.<br /><code>Allow Open Registration = " . esc_html (get_option ("users_can_register")) . "</code>, and <code>Default Role = " . esc_html (get_option ("default_role")) . "</code>.<br />For further details, see: <code>s2Member -› General Options -› Open Registration</code>.";
49
 
50
  $js = '<script type="text/javascript">';
51
- $js .= "jQuery('input#users_can_register, select#default_role').attr('disabled', 'disabled');";
52
  $js .= '</script>';
53
 
54
  do_action ("ws_plugin__s2member_during_general_ops_notice", get_defined_vars ());
@@ -81,7 +81,7 @@ if (!class_exists ("c_ws_plugin__s2member_op_notices"))
81
  $notice = "<em>* Note: The s2Member plugin has control over two options on this page.<br /><code>Allow Open Registration = " . esc_html (get_site_option ("registration")) . "</code> and <code>Add New Users = " . esc_html (get_site_option ("add_new_users")) . "</code>.<br />Please check: <code>s2Member -› Multisite (Config)</code>.";
82
 
83
  $js = '<script type="text/javascript">';
84
- $js .= "jQuery('input[name=registration], input#add_new_users').attr('disabled', 'disabled');";
85
  $js .= '</script>';
86
 
87
  do_action ("ws_plugin__s2member_during_multisite_ops_notice", get_defined_vars ());
@@ -114,19 +114,19 @@ if (!class_exists ("c_ws_plugin__s2member_op_notices"))
114
  do_action ("ws_plugin__s2member_during_reading_ops_notice", get_defined_vars ()); // Now check for conflicts.
115
 
116
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"] && (string)get_option ("page_on_front") === $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]
117
- && ($notice = '<strong>NOTE:</strong> Your Membership Options Page for s2Member is currently configured as your Home Page (i.e. static page) for WordPress®. This causes internal conflicts with s2Member. Your Membership Options Page MUST stand alone. Please correct this.'))
118
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice ($notice, "blog:" . $pagenow, true);
119
 
120
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"] && (string)get_option ("page_on_front") === $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"]
121
- && ($notice = '<strong>NOTE:</strong> Your Login Welcome Page for s2Member is currently configured as your Home Page (i.e. static page) for WordPress®. This causes internal conflicts with s2Member. Your Login Welcome Page MUST stand alone. Please correct this.'))
122
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice ($notice, "blog:" . $pagenow, true);
123
 
124
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"] && (string)get_option ("page_for_posts") === $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]
125
- && ($notice = '<strong>NOTE:</strong> Your Membership Options Page for s2Member is currently configured as your Posts Page (i.e. static page) for WordPress®. This causes internal conflicts with s2Member. Your Membership Options Page MUST stand alone. Please correct this.'))
126
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice ($notice, "blog:" . $pagenow, true);
127
 
128
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"] && (string)get_option ("page_for_posts") === $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"]
129
- && ($notice = '<strong>NOTE:</strong> Your Login Welcome Page for s2Member is currently configured as your Posts Page (i.e. static page) for WordPress®. This causes internal conflicts with s2Member. Your Login Welcome Page MUST stand alone. Please correct this.'))
130
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice ($notice, "blog:" . $pagenow, true);
131
  }
132
 
45
 
46
  if (is_blog_admin () && $pagenow === "options-general.php" && !isset ($_GET["page"]) && !is_multisite ()) // Multisite does NOT provide these options.
47
  {
48
+ $notice = "<em>* Note: The s2Member plugin has control over two options on this page.<br /><code>Anyone Can Register = " . esc_html (get_option ("users_can_register")) . "</code>, and <code>New User Default Role = " . esc_html (get_option ("default_role")) . "</code>.<br />For further details, see: <code>s2Member -› General Options -› Open Registration</code>.";
49
 
50
  $js = '<script type="text/javascript">';
51
+ $js .= "jQuery(document).ready(function(\$){ \$('input#users_can_register, select#default_role').attr('disabled', 'disabled'); });";
52
  $js .= '</script>';
53
 
54
  do_action ("ws_plugin__s2member_during_general_ops_notice", get_defined_vars ());
81
  $notice = "<em>* Note: The s2Member plugin has control over two options on this page.<br /><code>Allow Open Registration = " . esc_html (get_site_option ("registration")) . "</code> and <code>Add New Users = " . esc_html (get_site_option ("add_new_users")) . "</code>.<br />Please check: <code>s2Member -› Multisite (Config)</code>.";
82
 
83
  $js = '<script type="text/javascript">';
84
+ $js .= "jQuery(document).ready(function(\$){ \$('input[name=registration], input#add_new_users').attr('disabled', 'disabled'); });";
85
  $js .= '</script>';
86
 
87
  do_action ("ws_plugin__s2member_during_multisite_ops_notice", get_defined_vars ());
114
  do_action ("ws_plugin__s2member_during_reading_ops_notice", get_defined_vars ()); // Now check for conflicts.
115
 
116
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"] && (string)get_option ("page_on_front") === $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]
117
+ && ($notice = '<strong>NOTE:</strong> Your Membership Options Page for s2Member is currently configured as your Home Page (i.e. static page) for WordPress. This causes internal conflicts with s2Member. Your Membership Options Page MUST stand alone. Please correct this.'))
118
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice ($notice, "blog:" . $pagenow, true);
119
 
120
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"] && (string)get_option ("page_on_front") === $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"]
121
+ && ($notice = '<strong>NOTE:</strong> Your Login Welcome Page for s2Member is currently configured as your Home Page (i.e. static page) for WordPress. This causes internal conflicts with s2Member. Your Login Welcome Page MUST stand alone. Please correct this.'))
122
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice ($notice, "blog:" . $pagenow, true);
123
 
124
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"] && (string)get_option ("page_for_posts") === $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]
125
+ && ($notice = '<strong>NOTE:</strong> Your Membership Options Page for s2Member is currently configured as your Posts Page (i.e. static page) for WordPress. This causes internal conflicts with s2Member. Your Membership Options Page MUST stand alone. Please correct this.'))
126
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice ($notice, "blog:" . $pagenow, true);
127
 
128
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"] && (string)get_option ("page_for_posts") === $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_welcome_page"]
129
+ && ($notice = '<strong>NOTE:</strong> Your Login Welcome Page for s2Member is currently configured as your Posts Page (i.e. static page) for WordPress. This causes internal conflicts with s2Member. Your Login Welcome Page MUST stand alone. Please correct this.'))
130
  c_ws_plugin__s2member_admin_notices::enqueue_admin_notice ($notice, "blog:" . $pagenow, true);
131
  }
132
 
includes/classes/option-forces.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Forces WordPress® options.
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_option_forces"))
21
  {
22
  /**
23
- * Forces WordPress® options.
24
  *
25
  * @package s2Member\Option_Forces
26
  * @since 3.5
@@ -64,7 +64,7 @@ if (!class_exists ("c_ws_plugin__s2member_option_forces"))
64
  /**
65
  * Forces a specific Role to demote to, whenever a Member is demoted in one way or another.
66
  *
67
- * Use by the PayPal® IPN routines, and also by the Auto-EOT system.
68
  *
69
  * @package s2Member\Option_Forces
70
  * @since 3.5
1
  <?php
2
  /**
3
+ * Forces WordPress options.
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_option_forces"))
21
  {
22
  /**
23
+ * Forces WordPress options.
24
  *
25
  * @package s2Member\Option_Forces
26
  * @since 3.5
64
  /**
65
  * Forces a specific Role to demote to, whenever a Member is demoted in one way or another.
66
  *
67
+ * Use by the PayPal IPN routines, and also by the Auto-EOT system.
68
  *
69
  * @package s2Member\Option_Forces
70
  * @since 3.5
includes/classes/pages-sp.inc.php CHANGED
@@ -49,7 +49,7 @@ if (!class_exists ("c_ws_plugin__s2member_pages_sp"))
49
  {
50
  $page_uri = c_ws_plugin__s2member_utils_urls::parse_uri (get_page_link ($page_id)); // Get a full valid URI for this Page now.
51
 
52
- if (!c_ws_plugin__s2member_systematics_sp::is_wp_systematic_use_specific_page ($page_id, $page_uri)) // Do NOT touch WordPress® Systematics.
53
  {
54
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
55
 
@@ -69,7 +69,7 @@ if (!class_exists ("c_ws_plugin__s2member_pages_sp"))
69
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_pages"] === "all" && (!$check_user || !$user || !$user->has_cap ("access_s2member_level" . $n)))
70
  return apply_filters ("ws_plugin__s2member_check_specific_page_level_access", array ("s2member_level_req" => $n), get_defined_vars ());
71
 
72
- else if (strpos ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"], "all-") !== false && in_array ("all-pages", preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"])) && (!$check_user || !$user || !$user->has_cap ("access_s2member_level" . $n)))
73
  return apply_filters ("ws_plugin__s2member_check_specific_page_level_access", array ("s2member_level_req" => $n), get_defined_vars ());
74
 
75
  else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_pages"] && in_array ($page_id, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_pages"])) && (!$check_user || !$user || !$user->has_cap ("access_s2member_level" . $n)))
49
  {
50
  $page_uri = c_ws_plugin__s2member_utils_urls::parse_uri (get_page_link ($page_id)); // Get a full valid URI for this Page now.
51
 
52
+ if (!c_ws_plugin__s2member_systematics_sp::is_wp_systematic_use_specific_page ($page_id, $page_uri)) // Do NOT touch WordPress Systematics.
53
  {
54
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
55
 
69
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_pages"] === "all" && (!$check_user || !$user || !$user->has_cap ("access_s2member_level" . $n)))
70
  return apply_filters ("ws_plugin__s2member_check_specific_page_level_access", array ("s2member_level_req" => $n), get_defined_vars ());
71
 
72
+ else if (strpos ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"], "all-") !== false && (in_array ("all-page", preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"])) || in_array ("all-pages", preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"]))) && (!$check_user || !$user || !$user->has_cap ("access_s2member_level" . $n)))
73
  return apply_filters ("ws_plugin__s2member_check_specific_page_level_access", array ("s2member_level_req" => $n), get_defined_vars ());
74
 
75
  else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_pages"] && in_array ($page_id, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_pages"])) && (!$check_user || !$user || !$user->has_cap ("access_s2member_level" . $n)))
includes/classes/pages.inc.php CHANGED
@@ -45,7 +45,7 @@ if (!class_exists ("c_ws_plugin__s2member_pages"))
45
 
46
  if (!$excluded && is_page () && is_object ($post) && !empty ($post->ID) && ($page_id = (int)$post->ID) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
47
  {
48
- if (!c_ws_plugin__s2member_systematics::is_wp_systematic_use_page ()) // Do NOT touch WordPress® Systematics. This excludes all WordPress® Systematics.
49
  {
50
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
51
 
@@ -65,7 +65,7 @@ if (!class_exists ("c_ws_plugin__s2member_pages"))
65
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_pages"] === "all" && c_ws_plugin__s2member_no_cache::no_cache_constants (true) && (!$user || !$user->has_cap ("access_s2member_level" . $n)))
66
  c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars /* Configure MOP Vars here. */ ("page", $page_id, "level", $n, $_SERVER["REQUEST_URI"]) . exit ();
67
 
68
- else if (strpos ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"], "all-") && in_array ("all-pages", preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"])) && c_ws_plugin__s2member_no_cache::no_cache_constants (true) && (!$user || !$user->has_cap ("access_s2member_level" . $n)))
69
  c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars /* Configure MOP Vars here. */ ("page", $page_id, "level", $n, $_SERVER["REQUEST_URI"], "post") . exit ();
70
 
71
  else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_pages"] && in_array ($page_id, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_pages"])) && c_ws_plugin__s2member_no_cache::no_cache_constants (true) && (!$user || !$user->has_cap ("access_s2member_level" . $n)))
45
 
46
  if (!$excluded && is_page () && is_object ($post) && !empty ($post->ID) && ($page_id = (int)$post->ID) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
47
  {
48
+ if (!c_ws_plugin__s2member_systematics::is_wp_systematic_use_page ()) // Do NOT touch WordPress Systematics. This excludes all WordPress Systematics.
49
  {
50
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
51
 
65
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_pages"] === "all" && c_ws_plugin__s2member_no_cache::no_cache_constants (true) && (!$user || !$user->has_cap ("access_s2member_level" . $n)))
66
  c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars /* Configure MOP Vars here. */ ("page", $page_id, "level", $n, $_SERVER["REQUEST_URI"]) . exit ();
67
 
68
+ else if (strpos ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"], "all-") && (in_array ("all-page", preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"])) || in_array ("all-pages", preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"]))) && c_ws_plugin__s2member_no_cache::no_cache_constants (true) && (!$user || !$user->has_cap ("access_s2member_level" . $n)))
69
  c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars /* Configure MOP Vars here. */ ("page", $page_id, "level", $n, $_SERVER["REQUEST_URI"], "post") . exit ();
70
 
71
  else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_pages"] && in_array ($page_id, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_pages"])) && c_ws_plugin__s2member_no_cache::no_cache_constants (true) && (!$user || !$user->has_cap ("access_s2member_level" . $n)))
includes/classes/paypal-notify-in-cart.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_cart"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_cart"))
28
  class c_ws_plugin__s2member_paypal_notify_in_cart
29
  {
30
  /**
31
- * s2Member's PayPal® IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_cart"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_notify_in_cart
29
  {
30
  /**
31
+ * s2Member's PayPal IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
includes/classes/paypal-notify-in-express-checkout.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_express_checkout"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_express_checkout"))
28
  class c_ws_plugin__s2member_paypal_notify_in_express_checkout
29
  {
30
  /**
31
- * s2Member's PayPal® IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_express_checkout"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_notify_in_express_checkout
29
  {
30
  /**
31
+ * s2Member's PayPal IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
includes/classes/paypal-notify-in-rec-profile-creation-w-level.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_rec_profile_creation_w_level"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_rec_profile_creation_
28
  class c_ws_plugin__s2member_paypal_notify_in_rec_profile_creation_w_level
29
  {
30
  /**
31
- * s2Member's PayPal® IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_rec_profile_creation_w_level"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_notify_in_rec_profile_creation_w_level
29
  {
30
  /**
31
+ * s2Member's PayPal IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
includes/classes/paypal-notify-in-send-money.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_send_money"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_send_money"))
28
  class c_ws_plugin__s2member_paypal_notify_in_send_money
29
  {
30
  /**
31
- * s2Member's PayPal® IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_send_money"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_notify_in_send_money
29
  {
30
  /**
31
+ * s2Member's PayPal IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
includes/classes/paypal-notify-in-sp-refund-reversal.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_sp_refund_reversal"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_sp_refund_reversal"))
28
  class c_ws_plugin__s2member_paypal_notify_in_sp_refund_reversal
29
  {
30
  /**
31
- * s2Member's PayPal® IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_sp_refund_reversal"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_notify_in_sp_refund_reversal
29
  {
30
  /**
31
+ * s2Member's PayPal IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
includes/classes/paypal-notify-in-subscr-modify-w-level.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_modify_w_level"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_modify_w_level
28
  class c_ws_plugin__s2member_paypal_notify_in_subscr_modify_w_level
29
  {
30
  /**
31
- * s2Member's PayPal® IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
@@ -64,7 +64,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_modify_w_level
64
 
65
  $paypal["initial_term"] = (preg_match ("/^[1-9]/", $paypal["period1"])) ? $paypal["period1"] : "0 D"; // Defaults to "0 D" (zero days).
66
  $paypal["initial"] = (strlen ($paypal["mc_amount1"]) && preg_match ("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
67
- $paypal["regular"] = $paypal["mc_amount3"]; // This is the Regular Payment Amount that is charged to the Customer. Always required by PayPal®.
68
  $paypal["regular_term"] = $paypal["period3"]; // This is just set to keep a standard; this way both initial_term & regular_term are available.
69
  $paypal["recurring"] = ($paypal["recurring"]) ? $paypal["mc_amount3"] : "0"; // If non-recurring, this should be zero, otherwise Regular.
70
 
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_modify_w_level"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_notify_in_subscr_modify_w_level
29
  {
30
  /**
31
+ * s2Member's PayPal IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
64
 
65
  $paypal["initial_term"] = (preg_match ("/^[1-9]/", $paypal["period1"])) ? $paypal["period1"] : "0 D"; // Defaults to "0 D" (zero days).
66
  $paypal["initial"] = (strlen ($paypal["mc_amount1"]) && preg_match ("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
67
+ $paypal["regular"] = $paypal["mc_amount3"]; // This is the Regular Payment Amount that is charged to the Customer. Always required by PayPal.
68
  $paypal["regular_term"] = $paypal["period3"]; // This is just set to keep a standard; this way both initial_term & regular_term are available.
69
  $paypal["recurring"] = ($paypal["recurring"]) ? $paypal["mc_amount3"] : "0"; // If non-recurring, this should be zero, otherwise Regular.
70
 
includes/classes/paypal-notify-in-subscr-or-rp-cancellation-w-level.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_cancellation_w_level"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_cancella
28
  class c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_cancellation_w_level
29
  {
30
  /**
31
- * s2Member's PayPal® IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_cancellation_w_level"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_cancellation_w_level
29
  {
30
  /**
31
+ * s2Member's PayPal IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
includes/classes/paypal-notify-in-subscr-or-rp-eots-w-level.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if(realpath(__FILE__) === realpath($_SERVER["SCRIPT_FILENAME"]))
20
  if(!class_exists("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_eots_w_level"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_eots_w_lev
28
  class c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_eots_w_level
29
  {
30
  /**
31
- * s2Member's PayPal® IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
@@ -71,7 +71,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_eots_w_lev
71
  $paypal["s2member_log"][] = "s2Member `txn_type` identified as ".($identified_as = "( `subscr_eot|recurring_payment_expired|recurring_payment_suspended_due_to_max_failed_payment` ) - or - `recurring_payment_profile_cancel` w/ `initial_payment_status` ( `failed` )").".";
72
 
73
  $paypal["s2member_log"][] = "Sleeping for 5 seconds. Waiting for a possible ( `subscr_signup|subscr_modify|recurring_payment_profile_created` ).";
74
- sleep(5); // Sleep here for a moment. PayPal® sometimes sends a subscr_eot before the subscr_signup, subscr_modify.
75
  // 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.
76
  $paypal["s2member_log"][] = "Awake. It's ".date("D M j, Y g:i:s a T").". s2Member `txn_type` identified as ".$identified_as.".";
77
 
@@ -276,8 +276,8 @@ if(!class_exists("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_eots_w_lev
276
  $processing = $during = true; // Yes, we ARE processing this.
277
 
278
  $auto_eot_time = c_ws_plugin__s2member_utils_time::auto_eot_time($user_id, $paypal["period1"], $paypal["period3"], "", time());
279
- /* We assume the last payment was today, because this is how newer PayPal® accounts function with respect to EOT handling.
280
- Newer PayPal® accounts ( i.e. Subscription IDs starting with `I-`, will have their EOT triggered upon the last payment. */
281
  update_user_option($user_id, "s2member_auto_eot_time", $auto_eot_time); // s2Member will follow-up on this later.
282
 
283
  $paypal["s2member_log"][] = "Auto-EOT Time for this account (delayed), set to: ".date("D M j, Y g:i a T", $auto_eot_time);
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if(!class_exists("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_eots_w_level"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_eots_w_level
29
  {
30
  /**
31
+ * s2Member's PayPal IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
71
  $paypal["s2member_log"][] = "s2Member `txn_type` identified as ".($identified_as = "( `subscr_eot|recurring_payment_expired|recurring_payment_suspended_due_to_max_failed_payment` ) - or - `recurring_payment_profile_cancel` w/ `initial_payment_status` ( `failed` )").".";
72
 
73
  $paypal["s2member_log"][] = "Sleeping for 5 seconds. Waiting for a possible ( `subscr_signup|subscr_modify|recurring_payment_profile_created` ).";
74
+ sleep(5); // Sleep here for a moment. PayPal sometimes sends a subscr_eot before the subscr_signup, subscr_modify.
75
  // 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.
76
  $paypal["s2member_log"][] = "Awake. It's ".date("D M j, Y g:i:s a T").". s2Member `txn_type` identified as ".$identified_as.".";
77
 
276
  $processing = $during = true; // Yes, we ARE processing this.
277
 
278
  $auto_eot_time = c_ws_plugin__s2member_utils_time::auto_eot_time($user_id, $paypal["period1"], $paypal["period3"], "", time());
279
+ /* We assume the last payment was today, because this is how newer PayPal accounts function with respect to EOT handling.
280
+ Newer PayPal accounts ( i.e. Subscription IDs starting with `I-`, will have their EOT triggered upon the last payment. */
281
  update_user_option($user_id, "s2member_auto_eot_time", $auto_eot_time); // s2Member will follow-up on this later.
282
 
283
  $paypal["s2member_log"][] = "Auto-EOT Time for this account (delayed), set to: ".date("D M j, Y g:i a T", $auto_eot_time);
includes/classes/paypal-notify-in-subscr-or-rp-payment-failed-w-level.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_payment_failed_w_level"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_payment_
28
  class c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_payment_failed_w_level
29
  {
30
  /**
31
- * s2Member's PayPal® IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_payment_failed_w_level"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_payment_failed_w_level
29
  {
30
  /**
31
+ * s2Member's PayPal IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
includes/classes/paypal-notify-in-subscr-or-rp-payment-w-level.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_payment_w_level"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_payment_
28
  class c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_payment_w_level
29
  {
30
  /**
31
- * s2Member's PayPal® IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
@@ -58,7 +58,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_payment_
58
  {
59
  $paypal["s2member_log"][] = "s2Member `txn_type` identified as " . ($identified_as = "( `subscr_payment|recurring_payment` )") . ".";
60
  $paypal["s2member_log"][] = "Sleeping for 5 seconds. Waiting for a possible ( `subscr_signup|subscr_modify|recurring_payment_profile_created` ).";
61
- sleep (5); // Sleep here for a moment. PayPal® sometimes sends a subscr_payment before the subscr_signup, subscr_modify.
62
  // 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.
63
  $paypal["s2member_log"][] = "Awake. It's " . date ("D M j, Y g:i:s a T") . ". s2Member `txn_type` identified as " . $identified_as . ".";
64
 
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_payment_w_level"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_notify_in_subscr_or_rp_payment_w_level
29
  {
30
  /**
31
+ * s2Member's PayPal IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
58
  {
59
  $paypal["s2member_log"][] = "s2Member `txn_type` identified as " . ($identified_as = "( `subscr_payment|recurring_payment` )") . ".";
60
  $paypal["s2member_log"][] = "Sleeping for 5 seconds. Waiting for a possible ( `subscr_signup|subscr_modify|recurring_payment_profile_created` ).";
61
+ sleep (5); // Sleep here for a moment. PayPal sometimes sends a subscr_payment before the subscr_signup, subscr_modify.
62
  // 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.
63
  $paypal["s2member_log"][] = "Awake. It's " . date ("D M j, Y g:i:s a T") . ". s2Member `txn_type` identified as " . $identified_as . ".";
64
 
includes/classes/paypal-notify-in-subscr-or-wa-w-level.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_wa_w_level"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_wa_w_level"
28
  class c_ws_plugin__s2member_paypal_notify_in_subscr_or_wa_w_level
29
  {
30
  /**
31
- * s2Member's PayPal® IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
@@ -71,7 +71,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_wa_w_level"
71
  }
72
  $paypal["initial_term"] = (preg_match ("/^[1-9]/", $paypal["period1"])) ? $paypal["period1"] : /* Defaults to "0 D" (zero days). */ "0 D";
73
  $paypal["initial"] = (strlen ($paypal["mc_amount1"]) && preg_match ("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
74
- $paypal["regular"] = /* This is the Regular Payment Amount that is charged to the Customer. Always required by PayPal®. */$paypal["mc_amount3"];
75
  $paypal["regular_term"] = /* This is just set to keep a standard; this way both initial_term & regular_term are available. */ $paypal["period3"];
76
  $paypal["recurring"] = /* If non-recurring, this should be zero, otherwise Regular. */($paypal["recurring"]) ? $paypal["mc_amount3"] : "0";
77
 
@@ -81,7 +81,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_wa_w_level"
81
  */
82
  if /* Advanced way to handle Subscription mods. */ (preg_match ("/(referenc|associat|updat|upgrad)/i", $paypal["option_name1"]) && $paypal["option_selection1"])
83
  // 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.
84
- // PayPal® will not allow the `modify=1|2` parameter to be used in those scenarios, because technically there is no billing to update; only the account.
85
  {
86
  foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
87
  do_action ("ws_plugin__s2member_during_paypal_notify_before_subscr_signup_w_update_vars", get_defined_vars ());
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_subscr_or_wa_w_level"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_notify_in_subscr_or_wa_w_level
29
  {
30
  /**
31
+ * s2Member's PayPal IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
71
  }
72
  $paypal["initial_term"] = (preg_match ("/^[1-9]/", $paypal["period1"])) ? $paypal["period1"] : /* Defaults to "0 D" (zero days). */ "0 D";
73
  $paypal["initial"] = (strlen ($paypal["mc_amount1"]) && preg_match ("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
74
+ $paypal["regular"] = /* This is the Regular Payment Amount that is charged to the Customer. Always required by PayPal. */$paypal["mc_amount3"];
75
  $paypal["regular_term"] = /* This is just set to keep a standard; this way both initial_term & regular_term are available. */ $paypal["period3"];
76
  $paypal["recurring"] = /* If non-recurring, this should be zero, otherwise Regular. */($paypal["recurring"]) ? $paypal["mc_amount3"] : "0";
77
 
81
  */
82
  if /* Advanced way to handle Subscription mods. */ (preg_match ("/(referenc|associat|updat|upgrad)/i", $paypal["option_name1"]) && $paypal["option_selection1"])
83
  // 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.
84
+ // PayPal will not allow the `modify=1|2` parameter to be used in those scenarios, because technically there is no billing to update; only the account.
85
  {
86
  foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
87
  do_action ("ws_plugin__s2member_during_paypal_notify_before_subscr_signup_w_update_vars", get_defined_vars ());
includes/classes/paypal-notify-in-virtual-terminal.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_virtual_terminal"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_virtual_terminal"))
28
  class c_ws_plugin__s2member_paypal_notify_in_virtual_terminal
29
  {
30
  /**
31
- * s2Member's PayPal® IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_virtual_terminal"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_notify_in_virtual_terminal
29
  {
30
  /**
31
+ * s2Member's PayPal IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
includes/classes/paypal-notify-in-wa-ccaps-wo-level.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_wa_ccaps_wo_level"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110815
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_wa_ccaps_wo_level"))
28
  class c_ws_plugin__s2member_paypal_notify_in_wa_ccaps_wo_level
29
  {
30
  /**
31
- * s2Member's PayPal® IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110815
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_wa_ccaps_wo_level"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110815
28
  class c_ws_plugin__s2member_paypal_notify_in_wa_ccaps_wo_level
29
  {
30
  /**
31
+ * s2Member's PayPal IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110815
includes/classes/paypal-notify-in-web-accept-sp.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_web_accept_sp"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_web_accept_sp"))
28
  class c_ws_plugin__s2member_paypal_notify_in_web_accept_sp
29
  {
30
  /**
31
- * s2Member's PayPal® IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in_web_accept_sp"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_notify_in_web_accept_sp
29
  {
30
  /**
31
+ * s2Member's PayPal IPN handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
includes/classes/paypal-notify-in.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler (inner processing routines).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler (inner processing routines).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 3.5
@@ -28,14 +28,14 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in"))
28
  class c_ws_plugin__s2member_paypal_notify_in
29
  {
30
  /**
31
- * Handles PayPal® IPN processing.
32
  *
33
- * These same routines also handle s2Member Pro/PayPal® Pro operations;
34
  * giving you the ability *(as needed)* to Hook into these routines using
35
- * WordPress® Hooks/Filters; as seen in the source code below.
36
  *
37
  * Please do NOT modify the source code directly.
38
- * Instead, use WordPress® Hooks/Filters.
39
  *
40
  * For example, if you'd like to add your own custom conditionals, use:
41
  * ``add_filter ("ws_plugin__s2member_during_paypal_notify_conditionals", "your_function");``
@@ -65,7 +65,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in"))
65
  if (is_array ($paypal = c_ws_plugin__s2member_paypal_utilities::paypal_postvars ()) && ($_paypal = $paypal) && ($_paypal_s = serialize ($_paypal)))
66
  {
67
  $paypal["s2member_log"][] = "IPN received on: " . date ("D M j, Y g:i:s a T");
68
- $paypal["s2member_log"][] = "s2Member POST vars verified " . ((!empty ($paypal["proxy_verified"])) ? "with a Proxy Key" : "through a POST back to PayPal®.");
69
 
70
  $payment_status_issues = "/^(failed|denied|expired|refunded|partially_refunded|reversed|reversal|canceled_reversal|voided)$/i";
71
 
@@ -150,7 +150,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in"))
150
  else // Extensive log reporting here. This is an area where many site owners find trouble. Depending on server configuration; remote HTTPS connections may fail.
151
  {
152
  $paypal["s2member_log"][] = "Unable to verify \$_POST vars. This is most likely related to an invalid configuration of s2Member, or a problem with server compatibility.";
153
- $paypal["s2member_log"][] = "Please see this KB article: `http://www.s2member.com/kb/server-scanner/`. We suggest that you run the s2Member® Server Scanner.";
154
  $paypal["s2member_log"][] = var_export ($_REQUEST, true); // Recording _POST + _GET vars for analysis and debugging.
155
  }
156
  if ($email_configs_were_on) // Back on?
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler (inner processing routines).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify_in"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler (inner processing routines).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 3.5
28
  class c_ws_plugin__s2member_paypal_notify_in
29
  {
30
  /**
31
+ * Handles PayPal IPN processing.
32
  *
33
+ * These same routines also handle s2Member Pro/PayPal Pro operations;
34
  * giving you the ability *(as needed)* to Hook into these routines using
35
+ * WordPress Hooks/Filters; as seen in the source code below.
36
  *
37
  * Please do NOT modify the source code directly.
38
+ * Instead, use WordPress Hooks/Filters.
39
  *
40
  * For example, if you'd like to add your own custom conditionals, use:
41
  * ``add_filter ("ws_plugin__s2member_during_paypal_notify_conditionals", "your_function");``
65
  if (is_array ($paypal = c_ws_plugin__s2member_paypal_utilities::paypal_postvars ()) && ($_paypal = $paypal) && ($_paypal_s = serialize ($_paypal)))
66
  {
67
  $paypal["s2member_log"][] = "IPN received on: " . date ("D M j, Y g:i:s a T");
68
+ $paypal["s2member_log"][] = "s2Member POST vars verified " . ((!empty ($paypal["proxy_verified"])) ? "with a Proxy Key" : "through a POST back to PayPal.");
69
 
70
  $payment_status_issues = "/^(failed|denied|expired|refunded|partially_refunded|reversed|reversal|canceled_reversal|voided)$/i";
71
 
150
  else // Extensive log reporting here. This is an area where many site owners find trouble. Depending on server configuration; remote HTTPS connections may fail.
151
  {
152
  $paypal["s2member_log"][] = "Unable to verify \$_POST vars. This is most likely related to an invalid configuration of s2Member, or a problem with server compatibility.";
153
+ $paypal["s2member_log"][] = "Please see this KB article: `http://www.s2member.com/kb/server-scanner/`. We suggest that you run the s2Member Server Scanner.";
154
  $paypal["s2member_log"][] = var_export ($_REQUEST, true); // Recording _POST + _GET vars for analysis and debugging.
155
  }
156
  if ($email_configs_were_on) // Back on?
includes/classes/paypal-notify.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® IPN handler.
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify"))
21
  {
22
  /**
23
- * s2Member's PayPal® IPN handler.
24
  *
25
  * @package s2Member\PayPal
26
  * @since 3.5
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_notify"))
28
  class c_ws_plugin__s2member_paypal_notify
29
  {
30
  /**
31
- * Handles PayPal® IPN processing.
32
  *
33
  * @package s2Member\PayPal
34
  * @since 3.5
1
  <?php
2
  /**
3
+ * s2Member's PayPal IPN handler.
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_notify"))
21
  {
22
  /**
23
+ * s2Member's PayPal IPN handler.
24
  *
25
  * @package s2Member\PayPal
26
  * @since 3.5
28
  class c_ws_plugin__s2member_paypal_notify
29
  {
30
  /**
31
+ * Handles PayPal IPN processing.
32
  *
33
  * @package s2Member\PayPal
34
  * @since 3.5
includes/classes/paypal-return-in-no-tx-data.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_no_tx_data"))
21
  {
22
  /**
23
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_no_tx_data"))
28
  class c_ws_plugin__s2member_paypal_return_in_no_tx_data
29
  {
30
  /**
31
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
1
  <?php
2
  /**
3
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_no_tx_data"))
21
  {
22
  /**
23
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_return_in_no_tx_data
29
  {
30
  /**
31
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
includes/classes/paypal-return-in-proxy-ty-email.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_proxy_ty_email"))
21
  {
22
  /**
23
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_proxy_ty_email"))
28
  class c_ws_plugin__s2member_paypal_return_in_proxy_ty_email
29
  {
30
  /**
31
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
1
  <?php
2
  /**
3
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_proxy_ty_email"))
21
  {
22
  /**
23
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_return_in_proxy_ty_email
29
  {
30
  /**
31
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
includes/classes/paypal-return-in-proxy-x-preview.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_proxy_x_preview"))
21
  {
22
  /**
23
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_proxy_x_preview"))
28
  class c_ws_plugin__s2member_paypal_return_in_proxy_x_preview
29
  {
30
  /**
31
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
1
  <?php
2
  /**
3
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_proxy_x_preview"))
21
  {
22
  /**
23
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_return_in_proxy_x_preview
29
  {
30
  /**
31
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
includes/classes/paypal-return-in-subscr-modify-w-level.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if(realpath(__FILE__) === realpath($_SERVER["SCRIPT_FILENAME"]))
20
  if(!class_exists("c_ws_plugin__s2member_paypal_return_in_subscr_modify_w_level"))
21
  {
22
  /**
23
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_return_in_subscr_modify_w_level")
28
  class c_ws_plugin__s2member_paypal_return_in_subscr_modify_w_level
29
  {
30
  /**
31
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
@@ -71,7 +71,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_return_in_subscr_modify_w_level")
71
 
72
  $paypal["initial_term"] = (preg_match("/^[1-9]/", $paypal["period1"])) ? $paypal["period1"] : /* Defaults to "0 D" (zero days). */ "0 D";
73
  $paypal["initial"] = (strlen($paypal["mc_amount1"]) && preg_match("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
74
- $paypal["regular"] = /* This is the Regular Payment Amount that is charged to the Customer. Always required by PayPal®. */ $paypal["mc_amount3"];
75
  $paypal["regular_term"] = /* This is just set to keep a standard; this way both initial_term & regular_term are available. */ $paypal["period3"];
76
  $paypal["recurring"] = /* If non-recurring, this should be zero, otherwise Regular. */ ($paypal["recurring"]) ? $paypal["mc_amount3"] : "0";
77
 
1
  <?php
2
  /**
3
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if(!class_exists("c_ws_plugin__s2member_paypal_return_in_subscr_modify_w_level"))
21
  {
22
  /**
23
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_return_in_subscr_modify_w_level
29
  {
30
  /**
31
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
71
 
72
  $paypal["initial_term"] = (preg_match("/^[1-9]/", $paypal["period1"])) ? $paypal["period1"] : /* Defaults to "0 D" (zero days). */ "0 D";
73
  $paypal["initial"] = (strlen($paypal["mc_amount1"]) && preg_match("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
74
+ $paypal["regular"] = /* This is the Regular Payment Amount that is charged to the Customer. Always required by PayPal. */ $paypal["mc_amount3"];
75
  $paypal["regular_term"] = /* This is just set to keep a standard; this way both initial_term & regular_term are available. */ $paypal["period3"];
76
  $paypal["recurring"] = /* If non-recurring, this should be zero, otherwise Regular. */ ($paypal["recurring"]) ? $paypal["mc_amount3"] : "0";
77
 
includes/classes/paypal-return-in-subscr-or-wa-w-level.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if(realpath(__FILE__) === realpath($_SERVER["SCRIPT_FILENAME"]))
20
  if(!class_exists("c_ws_plugin__s2member_paypal_return_in_subscr_or_wa_w_level"))
21
  {
22
  /**
23
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_return_in_subscr_or_wa_w_level"))
28
  class c_ws_plugin__s2member_paypal_return_in_subscr_or_wa_w_level
29
  {
30
  /**
31
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
@@ -78,7 +78,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_return_in_subscr_or_wa_w_level"))
78
 
79
  $paypal["initial_term"] = (preg_match("/^[1-9]/", $paypal["period1"])) ? $paypal["period1"] : /* Defaults to "0 D" (zero days). */ "0 D";
80
  $paypal["initial"] = (strlen($paypal["mc_amount1"]) && preg_match("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
81
- $paypal["regular"] = /* This is the Regular Payment Amount that is charged to the Customer. Always required by PayPal®. */ $paypal["mc_amount3"];
82
  $paypal["regular_term"] = /* This is just set to keep a standard; this way both initial_term & regular_term are available. */ $paypal["period3"];
83
  $paypal["recurring"] = /* If non-recurring, this should be zero, otherwise Regular. */ ($paypal["recurring"]) ? $paypal["mc_amount3"] : "0";
84
 
@@ -98,7 +98,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_return_in_subscr_or_wa_w_level"))
98
  }
99
  $paypal["initial_term"] = (preg_match("/^[1-9]/", $paypal["period1"])) ? $paypal["period1"] : /* Defaults to "0 D" (zero days). */ "0 D";
100
  $paypal["initial"] = (strlen($paypal["mc_amount1"]) && preg_match("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
101
- $paypal["regular"] = /* This is the Regular Payment Amount that is charged to the Customer. Always required by PayPal®. */ $paypal["mc_amount3"];
102
  $paypal["regular_term"] = /* This is just set to keep a standard; this way both initial_term & regular_term are available. */ $paypal["period3"];
103
  $paypal["recurring"] = /* If non-recurring, this should be zero, otherwise Regular. */ ($paypal["recurring"]) ? $paypal["mc_amount3"] : "0";
104
 
1
  <?php
2
  /**
3
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if(!class_exists("c_ws_plugin__s2member_paypal_return_in_subscr_or_wa_w_level"))
21
  {
22
  /**
23
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_return_in_subscr_or_wa_w_level
29
  {
30
  /**
31
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
78
 
79
  $paypal["initial_term"] = (preg_match("/^[1-9]/", $paypal["period1"])) ? $paypal["period1"] : /* Defaults to "0 D" (zero days). */ "0 D";
80
  $paypal["initial"] = (strlen($paypal["mc_amount1"]) && preg_match("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
81
+ $paypal["regular"] = /* This is the Regular Payment Amount that is charged to the Customer. Always required by PayPal. */ $paypal["mc_amount3"];
82
  $paypal["regular_term"] = /* This is just set to keep a standard; this way both initial_term & regular_term are available. */ $paypal["period3"];
83
  $paypal["recurring"] = /* If non-recurring, this should be zero, otherwise Regular. */ ($paypal["recurring"]) ? $paypal["mc_amount3"] : "0";
84
 
98
  }
99
  $paypal["initial_term"] = (preg_match("/^[1-9]/", $paypal["period1"])) ? $paypal["period1"] : /* Defaults to "0 D" (zero days). */ "0 D";
100
  $paypal["initial"] = (strlen($paypal["mc_amount1"]) && preg_match("/^[1-9]/", $paypal["period1"])) ? $paypal["mc_amount1"] : $paypal["mc_amount3"];
101
+ $paypal["regular"] = /* This is the Regular Payment Amount that is charged to the Customer. Always required by PayPal. */ $paypal["mc_amount3"];
102
  $paypal["regular_term"] = /* This is just set to keep a standard; this way both initial_term & regular_term are available. */ $paypal["period3"];
103
  $paypal["recurring"] = /* If non-recurring, this should be zero, otherwise Regular. */ ($paypal["recurring"]) ? $paypal["mc_amount3"] : "0";
104
 
includes/classes/paypal-return-in-wa-ccaps-wo-level.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_wa_ccaps_wo_level"))
21
  {
22
  /**
23
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_wa_ccaps_wo_level"))
28
  class c_ws_plugin__s2member_paypal_return_in_wa_ccaps_wo_level
29
  {
30
  /**
31
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
1
  <?php
2
  /**
3
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_wa_ccaps_wo_level"))
21
  {
22
  /**
23
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_return_in_wa_ccaps_wo_level
29
  {
30
  /**
31
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
includes/classes/paypal-return-in-web-accept-sp.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_web_accept_sp"))
21
  {
22
  /**
23
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_web_accept_sp"))
28
  class c_ws_plugin__s2member_paypal_return_in_web_accept_sp
29
  {
30
  /**
31
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
1
  <?php
2
  /**
3
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_return_in_web_accept_sp"))
21
  {
22
  /**
23
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 110720
28
  class c_ws_plugin__s2member_paypal_return_in_web_accept_sp
29
  {
30
  /**
31
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routine).
32
  *
33
  * @package s2Member\PayPal
34
  * @since 110720
includes/classes/paypal-return-in.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routines).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_return_in"))
21
  {
22
  /**
23
- * s2Member's PayPal® Auto-Return/PDT handler (inner processing routines).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 3.5
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_return_in"))
28
  class c_ws_plugin__s2member_paypal_return_in
29
  {
30
  /**
31
- * Handles PayPal® Return URLs.
32
  *
33
  * @package s2Member\PayPal
34
  * @since 3.5
@@ -51,7 +51,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_return_in"))
51
  if (is_array ($paypal = c_ws_plugin__s2member_paypal_utilities::paypal_postvars ()) && ($_paypal = $paypal) && ($_paypal_s = serialize ($_paypal)))
52
  {
53
  $paypal["s2member_log"][] = "Return-Data received on: " . date ("D M j, Y g:i:s a T");
54
- $paypal["s2member_log"][] = "s2Member POST vars verified " . ((!empty ($paypal["proxy_verified"])) ? "with a Proxy Key" : "through a POST back to PayPal®.");
55
 
56
  $paypal["subscr_gateway"] = (!empty ($_GET["s2member_paypal_proxy"])) ? esc_html (trim (stripslashes ($_GET["s2member_paypal_proxy"]))) : "paypal";
57
 
@@ -97,7 +97,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_return_in"))
97
  else // Else, use the default ``$_SERVER["HTTP_HOST"]`` error.
98
  {
99
  if /* Enqueue an admin notice if the site owner is using the wrong domain variation. */ ($paypal["custom"] && ($paypal["custom"] === "www.".$_SERVER["HTTP_HOST"] || "www.".$paypal["custom"] === $_SERVER["HTTP_HOST"]))
100
- c_ws_plugin__s2member_admin_notices::enqueue_admin_notice("<strong>s2Member:</strong> Post-processing failed on at least one transaction. It appears that you have a PayPal® Button configured with a <code>custom=\"\"</code> Shortcode Attribute that does NOT match up with your installation domain name. If your site uses the <code>www.</code> prefix, please include that. If it does not, please exclude the <code>www.</code> prefix. You should have <code>custom=\"".preg_replace ("/\:([0-9]+)$/", "", $_SERVER["HTTP_HOST"])."\"</code>", "*:*", true);
101
 
102
  $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.';
103
 
@@ -120,17 +120,17 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_return_in"))
120
  else // Extensive log reporting here. This is an area where many site owners find trouble. Depending on server configuration; remote HTTPS connections may fail.
121
  {
122
  if /* Enqueue an admin notice if the site owner is missing the PDT Identity Key. */ (!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_identity_token"])
123
- c_ws_plugin__s2member_admin_notices::enqueue_admin_notice("<strong>s2Member:</strong> You have no PayPal® PDT Identity Token configured. PayPal® Auto-Return handling failed. Please update your PayPal® PDT Identity Key. See: <code>s2Member -› PayPal® Options -› PayPal® PDT/Auto-Return Integration</code>. Thank you!", "*:*", true);
124
 
125
  $paypal["s2member_log"][] = "Unable to verify \$_POST vars. This is most likely related to an invalid configuration of s2Member, or a problem with server compatibility.";
126
- $paypal["s2member_log"][] = "Please make sure that you configure a PayPal® PDT Identity Token for your installation of s2Member®. See: `s2Member -› PayPal® Options -› PayPal® PDT/Auto-Return Integration`.";
127
- $paypal["s2member_log"][] = "See also, this KB article: `http://www.s2member.com/kb/server-scanner/`. We suggest that you run the s2Member® Server Scanner.";
128
  $paypal["s2member_log"][] = /* Recording _POST + _GET vars for analysis and debugging. */ var_export ($_REQUEST, true);
129
 
130
  $paypal["s2member_log"][] = "Redirecting Customer to the Home Page (after displaying an error message).";
131
 
132
  echo c_ws_plugin__s2member_return_templates::return_template ("default",
133
- _x ('<strong>ERROR:</strong> Unable to verify <code>$_POST</code> vars.<br />Please contact Support for assistance.<br /><br />This is most likely related to an invalid configuration of s2Member, or a problem with server compatibility. If you are the site owner, and you\'re absolutely SURE that your configuration is valid, you may want to run some tests on your server, just to be sure <code>$_POST</code> variables are populated, and that your server is able to connect/communicate with your Payment Gateway over an HTTPS connection.<br /><br />s2Member uses the <code>WP_Http</code> class for remote connections; which will try to use <code>cURL</code> first, and then fall back on the <code>FOPEN</code> method when <code>cURL</code> is not available. On a Windows® server, you may have to disable your <code>cURL</code> extension; and instead, set <code>allow_url_fopen = yes</code> in your php.ini file. The <code>cURL</code> extension (usually) does NOT support SSL connections on a Windows® server.<br /><br />Please see <a href="http://www.s2member.com/forums/topic/ideal-server-configuration-for-s2member/" target="_blank">this thread</a> for details regarding the ideal server configuration for s2Member.', "s2member-front", "s2member"),
134
  _x ("Back To Home Page", "s2member-front", "s2member"), home_url ("/"));
135
  }
136
  /*
1
  <?php
2
  /**
3
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routines).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_return_in"))
21
  {
22
  /**
23
+ * s2Member's PayPal Auto-Return/PDT handler (inner processing routines).
24
  *
25
  * @package s2Member\PayPal
26
  * @since 3.5
28
  class c_ws_plugin__s2member_paypal_return_in
29
  {
30
  /**
31
+ * Handles PayPal Return URLs.
32
  *
33
  * @package s2Member\PayPal
34
  * @since 3.5
51
  if (is_array ($paypal = c_ws_plugin__s2member_paypal_utilities::paypal_postvars ()) && ($_paypal = $paypal) && ($_paypal_s = serialize ($_paypal)))
52
  {
53
  $paypal["s2member_log"][] = "Return-Data received on: " . date ("D M j, Y g:i:s a T");
54
+ $paypal["s2member_log"][] = "s2Member POST vars verified " . ((!empty ($paypal["proxy_verified"])) ? "with a Proxy Key" : "through a POST back to PayPal.");
55
 
56
  $paypal["subscr_gateway"] = (!empty ($_GET["s2member_paypal_proxy"])) ? esc_html (trim (stripslashes ($_GET["s2member_paypal_proxy"]))) : "paypal";
57
 
97
  else // Else, use the default ``$_SERVER["HTTP_HOST"]`` error.
98
  {
99
  if /* Enqueue an admin notice if the site owner is using the wrong domain variation. */ ($paypal["custom"] && ($paypal["custom"] === "www.".$_SERVER["HTTP_HOST"] || "www.".$paypal["custom"] === $_SERVER["HTTP_HOST"]))
100
+ c_ws_plugin__s2member_admin_notices::enqueue_admin_notice("<strong>s2Member:</strong> Post-processing failed on at least one transaction. It appears that you have a PayPal Button configured with a <code>custom=\"\"</code> Shortcode Attribute that does NOT match up with your installation domain name. If your site uses the <code>www.</code> prefix, please include that. If it does not, please exclude the <code>www.</code> prefix. You should have <code>custom=\"".preg_replace ("/\:([0-9]+)$/", "", $_SERVER["HTTP_HOST"])."\"</code>", "*:*", true);
101
 
102
  $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.';
103
 
120
  else // Extensive log reporting here. This is an area where many site owners find trouble. Depending on server configuration; remote HTTPS connections may fail.
121
  {
122
  if /* Enqueue an admin notice if the site owner is missing the PDT Identity Key. */ (!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_identity_token"])
123
+ c_ws_plugin__s2member_admin_notices::enqueue_admin_notice("<strong>s2Member:</strong> You have no PayPal PDT Identity Token configured. PayPal Auto-Return handling failed. Please update your PayPal PDT Identity Key. See: <code>s2Member -› PayPal Options -› PayPal PDT/Auto-Return Integration</code>. Thank you!", "*:*", true);
124
 
125
  $paypal["s2member_log"][] = "Unable to verify \$_POST vars. This is most likely related to an invalid configuration of s2Member, or a problem with server compatibility.";
126
+ $paypal["s2member_log"][] = "Please make sure that you configure a PayPal PDT Identity Token for your installation of s2Member. See: `s2Member -› PayPal Options -› PayPal PDT/Auto-Return Integration`.";
127
+ $paypal["s2member_log"][] = "See also, this KB article: `http://www.s2member.com/kb/server-scanner/`. We suggest that you run the s2Member Server Scanner.";
128
  $paypal["s2member_log"][] = /* Recording _POST + _GET vars for analysis and debugging. */ var_export ($_REQUEST, true);
129
 
130
  $paypal["s2member_log"][] = "Redirecting Customer to the Home Page (after displaying an error message).";
131
 
132
  echo c_ws_plugin__s2member_return_templates::return_template ("default",
133
+ _x ('<strong>ERROR:</strong> Unable to verify <code>$_POST</code> vars.<br />Please contact Support for assistance.<br /><br />This is most likely related to an invalid configuration of s2Member, or a problem with server compatibility. If you are the site owner, and you\'re absolutely SURE that your configuration is valid, you may want to run some tests on your server, just to be sure <code>$_POST</code> variables are populated, and that your server is able to connect/communicate with your Payment Gateway over an HTTPS connection.<br /><br />s2Member uses the <code>WP_Http</code> class for remote connections; which will try to use <code>cURL</code> first, and then fall back on the <code>FOPEN</code> method when <code>cURL</code> is not available. On a Windows server, you may have to disable your <code>cURL</code> extension; and instead, set <code>allow_url_fopen = yes</code> in your php.ini file. The <code>cURL</code> extension (usually) does NOT support SSL connections on a Windows server.<br /><br />Please see <a href="http://www.s2member.com/forums/topic/ideal-server-configuration-for-s2member/" target="_blank">this thread</a> for details regarding the ideal server configuration for s2Member.', "s2member-front", "s2member"),
134
  _x ("Back To Home Page", "s2member-front", "s2member"), home_url ("/"));
135
  }
136
  /*
includes/classes/paypal-return.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * s2Member's PayPal® Auto-Return/PDT handler.
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_return"))
21
  {
22
  /**
23
- * s2Member's PayPal® Auto-Return/PDT handler.
24
  *
25
  * @package s2Member\PayPal
26
  * @since 3.5
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_paypal_return"))
28
  class c_ws_plugin__s2member_paypal_return
29
  {
30
  /**
31
- * Handles PayPal® Return URLs.
32
  *
33
  * @package s2Member\PayPal
34
  * @since 3.5
1
  <?php
2
  /**
3
+ * s2Member's PayPal Auto-Return/PDT handler.
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_paypal_return"))
21
  {
22
  /**
23
+ * s2Member's PayPal Auto-Return/PDT handler.
24
  *
25
  * @package s2Member\PayPal
26
  * @since 3.5
28
  class c_ws_plugin__s2member_paypal_return
29
  {
30
  /**
31
+ * Handles PayPal Return URLs.
32
  *
33
  * @package s2Member\PayPal
34
  * @since 3.5
includes/classes/paypal-utilities.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * PayPal® utilities.
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if(realpath(__FILE__) === realpath($_SERVER["SCRIPT_FILENAME"]))
20
  if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
21
  {
22
  /**
23
- * PayPal® utilities.
24
  *
25
  * @package s2Member\PayPal
26
  * @since 3.5
@@ -28,7 +28,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
28
  class c_ws_plugin__s2member_paypal_utilities
29
  {
30
  /**
31
- * Get ``$_POST`` or ``$_REQUEST`` vars from PayPal®.
32
  *
33
  * @package s2Member\PayPal
34
  * @since 3.5
@@ -112,7 +112,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
112
  }
113
  }
114
  /**
115
- * Generates a PayPal® Proxy Key, for simulated IPN responses.
116
  *
117
  * @package s2Member\PayPal
118
  * @since 3.5
@@ -136,13 +136,13 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
136
  return apply_filters("ws_plugin__s2member_paypal_proxy_key_gen", $key, get_defined_vars());
137
  }
138
  /**
139
- * Calls upon the PayPal® API, and returns the response.
140
  *
141
  * @package s2Member\PayPal
142
  * @since 3.5
143
  *
144
- * @param array $post_vars An array of variables to send through the PayPal® API call.
145
- * @return array An array of variables returned by the PayPal® API.
146
  *
147
  * @todo Optimize this routine with ``empty()`` and ``isset()``.
148
  * @todo Possibly integrate this API: {@link http://msdn.microsoft.com/en-us/library/ff512417.aspx}.
@@ -160,7 +160,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
160
  $post_vars = apply_filters("ws_plugin__s2member_paypal_api_post_vars", $post_vars, get_defined_vars());
161
  $post_vars = (is_array($post_vars)) ? $post_vars : array();
162
 
163
- $post_vars["VERSION"] = /* Configure the PayPal® API version. */ "71.0";
164
  $post_vars["USER"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_username"];
165
  $post_vars["PWD"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_password"];
166
  $post_vars["SIGNATURE"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_signature"];
@@ -181,7 +181,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
181
  if(!$response["ACK"] || !preg_match("/^(Success|SuccessWithWarning)$/i", $response["ACK"]))
182
  {
183
  if(strlen($response["L_ERRORCODE0"]) || $response["L_SHORTMESSAGE0"] || $response["L_LONGMESSAGE0"])
184
- /* translators: Exclude `%2$s` and `%3$s`. These are English details returned by PayPal®. Replace `%2$s` and `%3$s` with: `Unable to process, please try again`, or something to that affect. Or, if you prefer, you could Filter ``$response["__error"]`` with `ws_plugin__s2member_paypal_api_response`. */
185
  $response["__error"] = sprintf(_x('Error #%1$s. %2$s. %3$s.', "s2member-front", "s2member"), $response["L_ERRORCODE0"], rtrim($response["L_SHORTMESSAGE0"], "."), rtrim($response["L_LONGMESSAGE0"], "."));
186
 
187
  else // Else, generate an error messsage - so something is reported back to the Customer.
@@ -210,15 +210,15 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
210
  return apply_filters("ws_plugin__s2member_paypal_api_response", c_ws_plugin__s2member_paypal_utilities::_paypal_api_response_filters($response), get_defined_vars());
211
  }
212
  /**
213
- * A sort of callback function that Filters PayPal® responses.
214
  *
215
  * Provides alternative explanations in some cases that require special attention.
216
  *
217
  * @package s2Member\PayPal
218
  * @since 3.5
219
  *
220
- * @param array $response Expects an array of response variables returned by the PayPal® API.
221
- * @return array An array of variables returned by the PayPal® API, after ``$response["__error"]`` is Filtered.
222
  */
223
  public static function _paypal_api_response_filters($response = FALSE)
224
  {
@@ -240,7 +240,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
240
  return /* Filters already applied with: ``ws_plugin__s2member_paypal_api_response``. */ $response;
241
  }
242
  /**
243
- * Cleans up values passed through PayPal® NVP strings.
244
  *
245
  * @package s2Member\PayPal
246
  * @since 121202
@@ -262,13 +262,13 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
262
  return apply_filters("ws_plugin__s2member_paypal_api_nv_cleanup", $value, get_defined_vars());
263
  }
264
  /**
265
- * Calls upon the PayPal® PayFlow API, and returns the response.
266
  *
267
  * @package s2Member\PayPal
268
  * @since 120514
269
  *
270
- * @param array $post_vars An array of variables to send through the PayPal® PayFlow API call.
271
- * @return array An array of variables returned by the PayPal® PayFlow API.
272
  */
273
  public static function paypal_payflow_api_response($post_vars = FALSE)
274
  {
@@ -310,7 +310,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
310
  if($response["RESULT"] !== "0")
311
  {
312
  if(strlen($response["RESPMSG"]))
313
- /* translators: Exclude `%2$s`. These are English details returned by PayPal®. Replace `%2$s` with: `Unable to process, please try again`, or something to that affect. Or, if you prefer, you could Filter ``$response["__error"]`` with `ws_plugin__s2member_paypal_payflow_api_response`. */
314
  $response["__error"] = sprintf(_x('Error #%1$s. %2$s.', "s2member-front", "s2member"), $response["RESULT"], rtrim($response["RESPMSG"], "."));
315
 
316
  else $response["__error"] = _x("Error. Please contact Support for assistance.", "s2member-front", "s2member");
@@ -318,7 +318,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
318
  else if(isset($response["TRXRESULT"]) && $response["TRXRESULT"] !== "0")
319
  {
320
  if(strlen($response["TRXRESPMSG"]))
321
- /* translators: Exclude `%2$s`. These are English details returned by PayPal®. Replace `%2$s` with: `Unable to process, please try again`, or something to that affect. Or, if you prefer, you could Filter ``$response["__error"]`` with `ws_plugin__s2member_paypal_payflow_api_response`. */
322
  $response["__error"] = sprintf(_x('Error #%1$s. %2$s.', "s2member-front", "s2member"), $response["TRXRESULT"], rtrim($response["TRXRESPMSG"], "."));
323
 
324
  else $response["__error"] = _x("Error. Please contact Support for assistance.", "s2member-front", "s2member");
@@ -347,15 +347,15 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
347
  return apply_filters("ws_plugin__s2member_paypal_payflow_api_response", c_ws_plugin__s2member_paypal_utilities::_paypal_payflow_api_response_filters($response), get_defined_vars());
348
  }
349
  /**
350
- * A sort of callback function that Filters Payflow® responses.
351
  *
352
  * Provides alternative explanations in some cases that require special attention.
353
  *
354
  * @package s2Member\PayPal
355
  * @since 120514
356
  *
357
- * @param array $response Expects an array of response variables returned by the Payflow® API.
358
- * @return array An array of variables returned by the Payflow® API, after ``$response["__error"]`` is Filtered.
359
  */
360
  public static function _paypal_payflow_api_response_filters($response = FALSE)
361
  {
@@ -372,7 +372,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
372
  return /* Filters already applied with: ``ws_plugin__s2member_paypal_payflow_api_response``. */ $response;
373
  }
374
  /**
375
- * Cleans up values passed through PayPal® text/namevalue strings.
376
  *
377
  * @package s2Member\PayPal
378
  * @since 121202
@@ -394,7 +394,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
394
  return apply_filters("ws_plugin__s2member_paypal_payflow_api_nv_cleanup", $value, get_defined_vars());
395
  }
396
  /**
397
- * Converts a term `D|W|M|Y` into PayPal® Pro format.
398
  *
399
  * @package s2Member\PayPal
400
  * @since 3.5
@@ -415,7 +415,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
415
  return apply_filters("ws_plugin__s2member_paypal_pro_term", $pro_term, get_defined_vars());
416
  }
417
  /**
418
- * Converts a term `D|W|M|Y` into Payflow® format.
419
  *
420
  * @package s2Member\PayPal
421
  * @since 120514
@@ -424,7 +424,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
424
  * @param str $period Expects a numeric value.
425
  * @return bool|str A full singular description of the term *( i.e. `DAY|WEEK|BIWK|MONT|QTER|SMYR|YEAR` )*, else false.
426
  *
427
- * @note Payflow® unfortunately does NOT support daily and/or bi-monthly billing.
428
  */
429
  public static function paypal_payflow_term($term = FALSE, $period = FALSE)
430
  {
@@ -448,7 +448,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
448
  return apply_filters("ws_plugin__s2member_paypal_payflow_term", $payflow_term, get_defined_vars());
449
  }
450
  /**
451
- * Converts a term `Day|Week|Month|Year` into PayPal® Standard format.
452
  *
453
  * @package s2Member\PayPal
454
  * @since 3.5
@@ -474,7 +474,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
474
  * @package s2Member\PayPal
475
  * @since 3.5
476
  *
477
- * @param str|array $array_or_string Either an array of PayPal® post vars, or a string.
478
  * @return str|bool A `subscr_id` string if non-empty, else false.
479
  */
480
  public static function paypal_pro_subscr_id($array_or_string = FALSE)
@@ -500,7 +500,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
500
  * @package s2Member\PayPal
501
  * @since 3.5
502
  *
503
- * @param str|array $array_or_string Either an array of PayPal® post vars, or a string.
504
  * If it's a string, we make sure it is a valid `level:ccaps:eotper` or `sp:ids:expiration` combination.
505
  * @return str|bool An `item_number` string if non-empty, else false.
506
  */
@@ -510,7 +510,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
510
  do_action("ws_plugin__s2member_before_paypal_pro_item_number", get_defined_vars());
511
  unset /* Unset defined __refs, __v. */($__refs, $__v);
512
 
513
- if(isset($array_or_string["PROFILENAME"]) /* Payflow® API alternative. */)
514
  $array_or_string["PROFILEREFERENCE"] = $array_or_string["PROFILENAME"];
515
 
516
  if(is_array($array = $array_or_string) && (!empty($array["PROFILEREFERENCE"]) || !empty($array["rp_invoice_id"])))
@@ -539,7 +539,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
539
  * @package s2Member\PayPal
540
  * @since 3.5
541
  *
542
- * @param str|array $array_or_string Either an array of PayPal® post vars, or a string.
543
  * @return str|bool An `item_name` string if non-empty, else false.
544
  */
545
  public static function paypal_pro_item_name($array_or_string = FALSE)
@@ -571,7 +571,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
571
  * @package s2Member\PayPal
572
  * @since 3.5
573
  *
574
- * @param str|array $array_or_string Either an array of PayPal® post vars, or a string.
575
  * If it's a string, we make sure it is a valid `period term` combination.
576
  * @param str $default Optional. Value if unavailable. Defaults to `0 D`.
577
  * @return str A `period1` string if possible, or defaults to `0 D`.
@@ -582,7 +582,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
582
  do_action("ws_plugin__s2member_before_paypal_pro_period1", get_defined_vars());
583
  unset /* Unset defined __refs, __v. */($__refs, $__v);
584
 
585
- if(isset($array_or_string["PROFILENAME"]) /* Payflow® API alternative. */)
586
  $array_or_string["PROFILEREFERENCE"] = $array_or_string["PROFILENAME"];
587
 
588
  if(is_array($array = $array_or_string) && (!empty($array["PROFILEREFERENCE"]) || !empty($array["rp_invoice_id"])))
@@ -625,7 +625,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
625
  * @package s2Member\PayPal
626
  * @since 3.5
627
  *
628
- * @param str|array $array_or_string Either an array of PayPal® post vars, or a string.
629
  * If it's a string, we make sure it is a valid `period term` combination.
630
  * @param str $default Optional. Value if unavailable. Defaults to `1 D`.
631
  * @return str A `period3` string if possible, or defaults to `1 D`.
@@ -636,7 +636,7 @@ if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
636
  do_action("ws_plugin__s2member_before_paypal_pro_period3", get_defined_vars());
637
  unset /* Unset defined __refs, __v. */($__refs, $__v);
638
 
639
- if(isset($array_or_string["PROFILENAME"]) /* Payflow® API alternative. */)
640
  $array_or_string["PROFILEREFERENCE"] = $array_or_string["PROFILENAME"];
641
 
642
  if(is_array($array = $array_or_string) && (!empty($array["PROFILEREFERENCE"]) || !empty($array["rp_invoice_id"])))
1
  <?php
2
  /**
3
+ * PayPal utilities.
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if(!class_exists("c_ws_plugin__s2member_paypal_utilities"))
21
  {
22
  /**
23
+ * PayPal utilities.
24
  *
25
  * @package s2Member\PayPal
26
  * @since 3.5
28
  class c_ws_plugin__s2member_paypal_utilities
29
  {
30
  /**
31
+ * Get ``$_POST`` or ``$_REQUEST`` vars from PayPal.
32
  *
33
  * @package s2Member\PayPal
34
  * @since 3.5
112
  }
113
  }
114
  /**
115
+ * Generates a PayPal Proxy Key, for simulated IPN responses.
116
  *
117
  * @package s2Member\PayPal
118
  * @since 3.5
136
  return apply_filters("ws_plugin__s2member_paypal_proxy_key_gen", $key, get_defined_vars());
137
  }
138
  /**
139
+ * Calls upon the PayPal API, and returns the response.
140
  *
141
  * @package s2Member\PayPal
142
  * @since 3.5
143
  *
144
+ * @param array $post_vars An array of variables to send through the PayPal API call.
145
+ * @return array An array of variables returned by the PayPal API.
146
  *
147
  * @todo Optimize this routine with ``empty()`` and ``isset()``.
148
  * @todo Possibly integrate this API: {@link http://msdn.microsoft.com/en-us/library/ff512417.aspx}.
160
  $post_vars = apply_filters("ws_plugin__s2member_paypal_api_post_vars", $post_vars, get_defined_vars());
161
  $post_vars = (is_array($post_vars)) ? $post_vars : array();
162
 
163
+ $post_vars["VERSION"] = /* Configure the PayPal API version. */ "71.0";
164
  $post_vars["USER"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_username"];
165
  $post_vars["PWD"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_password"];
166
  $post_vars["SIGNATURE"] = $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_signature"];
181
  if(!$response["ACK"] || !preg_match("/^(Success|SuccessWithWarning)$/i", $response["ACK"]))
182
  {
183
  if(strlen($response["L_ERRORCODE0"]) || $response["L_SHORTMESSAGE0"] || $response["L_LONGMESSAGE0"])
184
+ /* translators: Exclude `%2$s` and `%3$s`. These are English details returned by PayPal. Replace `%2$s` and `%3$s` with: `Unable to process, please try again`, or something to that affect. Or, if you prefer, you could Filter ``$response["__error"]`` with `ws_plugin__s2member_paypal_api_response`. */
185
  $response["__error"] = sprintf(_x('Error #%1$s. %2$s. %3$s.', "s2member-front", "s2member"), $response["L_ERRORCODE0"], rtrim($response["L_SHORTMESSAGE0"], "."), rtrim($response["L_LONGMESSAGE0"], "."));
186
 
187
  else // Else, generate an error messsage - so something is reported back to the Customer.
210
  return apply_filters("ws_plugin__s2member_paypal_api_response", c_ws_plugin__s2member_paypal_utilities::_paypal_api_response_filters($response), get_defined_vars());
211
  }
212
  /**
213
+ * A sort of callback function that Filters PayPal responses.
214
  *
215
  * Provides alternative explanations in some cases that require special attention.
216
  *
217
  * @package s2Member\PayPal
218
  * @since 3.5
219
  *
220
+ * @param array $response Expects an array of response variables returned by the PayPal API.
221
+ * @return array An array of variables returned by the PayPal API, after ``$response["__error"]`` is Filtered.
222
  */
223
  public static function _paypal_api_response_filters($response = FALSE)
224
  {
240
  return /* Filters already applied with: ``ws_plugin__s2member_paypal_api_response``. */ $response;
241
  }
242
  /**
243
+ * Cleans up values passed through PayPal NVP strings.
244
  *
245
  * @package s2Member\PayPal
246
  * @since 121202
262
  return apply_filters("ws_plugin__s2member_paypal_api_nv_cleanup", $value, get_defined_vars());
263
  }
264
  /**
265
+ * Calls upon the PayPal PayFlow API, and returns the response.
266
  *
267
  * @package s2Member\PayPal
268
  * @since 120514
269
  *
270
+ * @param array $post_vars An array of variables to send through the PayPal PayFlow API call.
271
+ * @return array An array of variables returned by the PayPal PayFlow API.
272
  */
273
  public static function paypal_payflow_api_response($post_vars = FALSE)
274
  {
310
  if($response["RESULT"] !== "0")
311
  {
312
  if(strlen($response["RESPMSG"]))
313
+ /* translators: Exclude `%2$s`. These are English details returned by PayPal. Replace `%2$s` with: `Unable to process, please try again`, or something to that affect. Or, if you prefer, you could Filter ``$response["__error"]`` with `ws_plugin__s2member_paypal_payflow_api_response`. */
314
  $response["__error"] = sprintf(_x('Error #%1$s. %2$s.', "s2member-front", "s2member"), $response["RESULT"], rtrim($response["RESPMSG"], "."));
315
 
316
  else $response["__error"] = _x("Error. Please contact Support for assistance.", "s2member-front", "s2member");
318
  else if(isset($response["TRXRESULT"]) && $response["TRXRESULT"] !== "0")
319
  {
320
  if(strlen($response["TRXRESPMSG"]))
321
+ /* translators: Exclude `%2$s`. These are English details returned by PayPal. Replace `%2$s` with: `Unable to process, please try again`, or something to that affect. Or, if you prefer, you could Filter ``$response["__error"]`` with `ws_plugin__s2member_paypal_payflow_api_response`. */
322
  $response["__error"] = sprintf(_x('Error #%1$s. %2$s.', "s2member-front", "s2member"), $response["TRXRESULT"], rtrim($response["TRXRESPMSG"], "."));
323
 
324
  else $response["__error"] = _x("Error. Please contact Support for assistance.", "s2member-front", "s2member");
347
  return apply_filters("ws_plugin__s2member_paypal_payflow_api_response", c_ws_plugin__s2member_paypal_utilities::_paypal_payflow_api_response_filters($response), get_defined_vars());
348
  }
349
  /**
350
+ * A sort of callback function that Filters Payflow responses.
351
  *
352
  * Provides alternative explanations in some cases that require special attention.
353
  *
354
  * @package s2Member\PayPal
355
  * @since 120514
356
  *
357
+ * @param array $response Expects an array of response variables returned by the Payflow API.
358
+ * @return array An array of variables returned by the Payflow API, after ``$response["__error"]`` is Filtered.
359
  */
360
  public static function _paypal_payflow_api_response_filters($response = FALSE)
361
  {
372
  return /* Filters already applied with: ``ws_plugin__s2member_paypal_payflow_api_response``. */ $response;
373
  }
374
  /**
375
+ * Cleans up values passed through PayPal text/namevalue strings.
376
  *
377
  * @package s2Member\PayPal
378
  * @since 121202
394
  return apply_filters("ws_plugin__s2member_paypal_payflow_api_nv_cleanup", $value, get_defined_vars());
395
  }
396
  /**
397
+ * Converts a term `D|W|M|Y` into PayPal Pro format.
398
  *
399
  * @package s2Member\PayPal
400
  * @since 3.5
415
  return apply_filters("ws_plugin__s2member_paypal_pro_term", $pro_term, get_defined_vars());
416
  }
417
  /**
418
+ * Converts a term `D|W|M|Y` into Payflow format.
419
  *
420
  * @package s2Member\PayPal
421
  * @since 120514
424
  * @param str $period Expects a numeric value.
425
  * @return bool|str A full singular description of the term *( i.e. `DAY|WEEK|BIWK|MONT|QTER|SMYR|YEAR` )*, else false.
426
  *
427
+ * @note Payflow unfortunately does NOT support daily and/or bi-monthly billing.
428
  */
429
  public static function paypal_payflow_term($term = FALSE, $period = FALSE)
430
  {
448
  return apply_filters("ws_plugin__s2member_paypal_payflow_term", $payflow_term, get_defined_vars());
449
  }
450
  /**
451
+ * Converts a term `Day|Week|Month|Year` into PayPal Standard format.
452
  *
453
  * @package s2Member\PayPal
454
  * @since 3.5
474
  * @package s2Member\PayPal
475
  * @since 3.5
476
  *
477
+ * @param str|array $array_or_string Either an array of PayPal post vars, or a string.
478
  * @return str|bool A `subscr_id` string if non-empty, else false.
479
  */
480
  public static function paypal_pro_subscr_id($array_or_string = FALSE)
500
  * @package s2Member\PayPal
501
  * @since 3.5
502
  *
503
+ * @param str|array $array_or_string Either an array of PayPal post vars, or a string.
504
  * If it's a string, we make sure it is a valid `level:ccaps:eotper` or `sp:ids:expiration` combination.
505
  * @return str|bool An `item_number` string if non-empty, else false.
506
  */
510
  do_action("ws_plugin__s2member_before_paypal_pro_item_number", get_defined_vars());
511
  unset /* Unset defined __refs, __v. */($__refs, $__v);
512
 
513
+ if(isset($array_or_string["PROFILENAME"]) /* Payflow API alternative. */)
514
  $array_or_string["PROFILEREFERENCE"] = $array_or_string["PROFILENAME"];
515
 
516
  if(is_array($array = $array_or_string) && (!empty($array["PROFILEREFERENCE"]) || !empty($array["rp_invoice_id"])))
539
  * @package s2Member\PayPal
540
  * @since 3.5
541
  *
542
+ * @param str|array $array_or_string Either an array of PayPal post vars, or a string.
543
  * @return str|bool An `item_name` string if non-empty, else false.
544
  */
545
  public static function paypal_pro_item_name($array_or_string = FALSE)
571
  * @package s2Member\PayPal
572
  * @since 3.5
573
  *
574
+ * @param str|array $array_or_string Either an array of PayPal post vars, or a string.
575
  * If it's a string, we make sure it is a valid `period term` combination.
576
  * @param str $default Optional. Value if unavailable. Defaults to `0 D`.
577
  * @return str A `period1` string if possible, or defaults to `0 D`.
582
  do_action("ws_plugin__s2member_before_paypal_pro_period1", get_defined_vars());
583
  unset /* Unset defined __refs, __v. */($__refs, $__v);
584
 
585
+ if(isset($array_or_string["PROFILENAME"]) /* Payflow API alternative. */)
586
  $array_or_string["PROFILEREFERENCE"] = $array_or_string["PROFILENAME"];
587
 
588
  if(is_array($array = $array_or_string) && (!empty($array["PROFILEREFERENCE"]) || !empty($array["rp_invoice_id"])))
625
  * @package s2Member\PayPal
626
  * @since 3.5
627
  *
628
+ * @param str|array $array_or_string Either an array of PayPal post vars, or a string.
629
  * If it's a string, we make sure it is a valid `period term` combination.
630
  * @param str $default Optional. Value if unavailable. Defaults to `1 D`.
631
  * @return str A `period3` string if possible, or defaults to `1 D`.
636
  do_action("ws_plugin__s2member_before_paypal_pro_period3", get_defined_vars());
637
  unset /* Unset defined __refs, __v. */($__refs, $__v);
638
 
639
+ if(isset($array_or_string["PROFILENAME"]) /* Payflow API alternative. */)
640
  $array_or_string["PROFILEREFERENCE"] = $array_or_string["PROFILENAME"];
641
 
642
  if(is_array($array = $array_or_string) && (!empty($array["PROFILEREFERENCE"]) || !empty($array["rp_invoice_id"])))
includes/classes/posts-sp.inc.php CHANGED
@@ -47,7 +47,7 @@ if (!class_exists ("c_ws_plugin__s2member_posts_sp"))
47
  {
48
  $post_uri = c_ws_plugin__s2member_utils_urls::parse_uri (get_permalink ($post_id)); // Get a full valid URI for this Post now.
49
 
50
- if (!c_ws_plugin__s2member_systematics_sp::is_wp_systematic_use_specific_page ($post_id, $post_uri)) // Do NOT touch WordPress® Systematics.
51
  {
52
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
53
 
@@ -61,7 +61,7 @@ if (!class_exists ("c_ws_plugin__s2member_posts_sp"))
61
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"] === "all" && (!$check_user || !$user || !$user->has_cap ("access_s2member_level" . $n)))
62
  return apply_filters ("ws_plugin__s2member_check_specific_post_level_access", array ("s2member_level_req" => $n), get_defined_vars ());
63
 
64
- else if (strpos ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"], "all-") !== false && ($post_type = get_post_type ($post_id)) && in_array ("all-" . $post_type . "s", preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"])) && (!$check_user || !$user || !$user->has_cap ("access_s2member_level" . $n)))
65
  return apply_filters ("ws_plugin__s2member_check_specific_post_level_access", array ("s2member_level_req" => $n), get_defined_vars ());
66
 
67
  else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"] && in_array ($post_id, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"])) && (!$check_user || !$user || !$user->has_cap ("access_s2member_level" . $n)))
47
  {
48
  $post_uri = c_ws_plugin__s2member_utils_urls::parse_uri (get_permalink ($post_id)); // Get a full valid URI for this Post now.
49
 
50
+ if (!c_ws_plugin__s2member_systematics_sp::is_wp_systematic_use_specific_page ($post_id, $post_uri)) // Do NOT touch WordPress Systematics.
51
  {
52
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
53
 
61
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"] === "all" && (!$check_user || !$user || !$user->has_cap ("access_s2member_level" . $n)))
62
  return apply_filters ("ws_plugin__s2member_check_specific_post_level_access", array ("s2member_level_req" => $n), get_defined_vars ());
63
 
64
+ else if (strpos ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"], "all-") !== false && ($post_type = get_post_type ($post_id)) && (in_array ("all-" . $post_type, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"])) || in_array ("all-" . $post_type . "s", preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"]))) && (!$check_user || !$user || !$user->has_cap ("access_s2member_level" . $n)))
65
  return apply_filters ("ws_plugin__s2member_check_specific_post_level_access", array ("s2member_level_req" => $n), get_defined_vars ());
66
 
67
  else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"] && in_array ($post_id, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"])) && (!$check_user || !$user || !$user->has_cap ("access_s2member_level" . $n)))
includes/classes/posts.inc.php CHANGED
@@ -45,7 +45,7 @@ if (!class_exists ("c_ws_plugin__s2member_posts"))
45
 
46
  if (!$excluded && is_single () && is_object ($post) && !empty ($post->ID) && ($post_id = (int)$post->ID) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
47
  {
48
- if (!c_ws_plugin__s2member_systematics::is_wp_systematic_use_page ()) // Do NOT touch WordPress® Systematics. This excludes all WordPress® Systematics.
49
  {
50
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
51
 
@@ -59,7 +59,7 @@ if (!class_exists ("c_ws_plugin__s2member_posts"))
59
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"] === "all" && c_ws_plugin__s2member_no_cache::no_cache_constants (true) && (!$user || !$user->has_cap ("access_s2member_level" . $n)))
60
  c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars /* Configure MOP Vars here. */ ("post", $post_id, "level", $n, $_SERVER["REQUEST_URI"]) . exit ();
61
 
62
- else if (strpos ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"], "all-") !== false && in_array ("all-" . $post->post_type . "s", preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"])) && c_ws_plugin__s2member_no_cache::no_cache_constants (true) && (!$user || !$user->has_cap ("access_s2member_level" . $n)))
63
  c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars /* Configure MOP Vars here. */ ("post", $post_id, "level", $n, $_SERVER["REQUEST_URI"]) . exit ();
64
 
65
  else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"] && in_array ($post_id, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"])) && c_ws_plugin__s2member_no_cache::no_cache_constants (true) && (!$user || !$user->has_cap ("access_s2member_level" . $n)))
45
 
46
  if (!$excluded && is_single () && is_object ($post) && !empty ($post->ID) && ($post_id = (int)$post->ID) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
47
  {
48
+ if (!c_ws_plugin__s2member_systematics::is_wp_systematic_use_page ()) // Do NOT touch WordPress Systematics. This excludes all WordPress Systematics.
49
  {
50
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
51
 
59
  if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"] === "all" && c_ws_plugin__s2member_no_cache::no_cache_constants (true) && (!$user || !$user->has_cap ("access_s2member_level" . $n)))
60
  c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars /* Configure MOP Vars here. */ ("post", $post_id, "level", $n, $_SERVER["REQUEST_URI"]) . exit ();
61
 
62
+ else if (strpos ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"], "all-") !== false && (in_array ("all-" . $post->post_type, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"])) || in_array ("all-" . $post->post_type . "s", preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"]))) && c_ws_plugin__s2member_no_cache::no_cache_constants (true) && (!$user || !$user->has_cap ("access_s2member_level" . $n)))
63
  c_ws_plugin__s2member_mo_page::wp_redirect_w_mop_vars /* Configure MOP Vars here. */ ("post", $post_id, "level", $n, $_SERVER["REQUEST_URI"]) . exit ();
64
 
65
  else if ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"] && in_array ($post_id, preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"])) && c_ws_plugin__s2member_no_cache::no_cache_constants (true) && (!$user || !$user->has_cap ("access_s2member_level" . $n)))
includes/classes/ptags-sp.inc.php CHANGED
@@ -66,7 +66,7 @@ if (!class_exists ("c_ws_plugin__s2member_ptags_sp"))
66
  {
67
  $tag_uri = c_ws_plugin__s2member_utils_urls::parse_uri (get_tag_link ($tag_id)); // Get a full valid URI for this Tag.
68
 
69
- if (!c_ws_plugin__s2member_systematics_sp::is_wp_systematic_use_specific_page (null, $tag_uri)) // Do NOT touch WordPress® Systematics.
70
  {
71
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
72
 
66
  {
67
  $tag_uri = c_ws_plugin__s2member_utils_urls::parse_uri (get_tag_link ($tag_id)); // Get a full valid URI for this Tag.
68
 
69
+ if (!c_ws_plugin__s2member_systematics_sp::is_wp_systematic_use_specific_page (null, $tag_uri)) // Do NOT touch WordPress Systematics.
70
  {
71
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
72
 
includes/classes/ptags.inc.php CHANGED
@@ -45,7 +45,7 @@ if (!class_exists ("c_ws_plugin__s2member_ptags"))
45
 
46
  if (!$excluded && is_tag () && is_object ($tag = $wp_query->get_queried_object ()) && !empty ($tag->term_id) && ($tag_id = (int)$tag->term_id) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
47
  {
48
- if (!c_ws_plugin__s2member_systematics::is_wp_systematic_use_page ()) // Do NOT touch WordPress® Systematics. This excludes all WordPress® Systematics.
49
  {
50
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
51
 
45
 
46
  if (!$excluded && is_tag () && is_object ($tag = $wp_query->get_queried_object ()) && !empty ($tag->term_id) && ($tag_id = (int)$tag->term_id) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
47
  {
48
+ if (!c_ws_plugin__s2member_systematics::is_wp_systematic_use_page ()) // Do NOT touch WordPress Systematics. This excludes all WordPress Systematics.
49
  {
50
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
51
 
includes/classes/querys.inc.php CHANGED
@@ -28,7 +28,7 @@ if(!class_exists("c_ws_plugin__s2member_querys"))
28
  class c_ws_plugin__s2member_querys
29
  {
30
  /**
31
- * The current WordPress® query object reference.
32
  *
33
  * @package s2Member\Queries
34
  * @since 110912
@@ -65,7 +65,7 @@ if(!class_exists("c_ws_plugin__s2member_querys"))
65
  return; // For uniformity.
66
  }
67
  /**
68
- * Filter all WordPress® queries.
69
  *
70
  * s2Member respects the query var: `suppress_filters`.
71
  * If you need to make a query without it being Filtered, use ``$wp_query->set ("suppress_filters", true);``.
@@ -205,9 +205,10 @@ if(!class_exists("c_ws_plugin__s2member_querys"))
205
  else if($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level".$n."_posts"] && (!$user || !current_user_can("access_s2member_level".$n)))
206
  {
207
  foreach(($_posts = preg_split("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level".$n."_posts"])) as $_p)
208
- if(strpos($_p, "all-") === 0 && preg_match("/^all-(.+)$/", $_p, $_m) /* Protecting `all-` of a specific Post Type? */)
209
- if(is_array($_p_of_type = c_ws_plugin__s2member_utils_gets::get_all_post_ids($_m[1])) && !empty($_p_of_type))
210
- $_posts = array_merge /* Merge all Posts of this Post Type. */($_posts, $_p_of_type);
 
211
 
212
  $_posts = array_unique( /* Force integers. */c_ws_plugin__s2member_utils_arrays::force_integers($_posts));
213
 
@@ -292,7 +293,7 @@ if(!class_exists("c_ws_plugin__s2member_querys"))
292
  return; // For uniformity.
293
  }
294
  /**
295
- * Filters WordPress® navigation menu items.
296
  *
297
  * @package s2Member\Queries
298
  * @since 110912
@@ -376,7 +377,7 @@ if(!class_exists("c_ws_plugin__s2member_querys"))
376
  return apply_filters("_ws_plugin__s2member_is_admin_ajax_search", false, get_defined_vars());
377
  }
378
  /**
379
- * Filters WordPress® Page queries that use wp_list_pages()
380
  *
381
  * @package s2Member\Queries
382
  * @since 130617
28
  class c_ws_plugin__s2member_querys
29
  {
30
  /**
31
+ * The current WordPress query object reference.
32
  *
33
  * @package s2Member\Queries
34
  * @since 110912
65
  return; // For uniformity.
66
  }
67
  /**
68
+ * Filter all WordPress queries.
69
  *
70
  * s2Member respects the query var: `suppress_filters`.
71
  * If you need to make a query without it being Filtered, use ``$wp_query->set ("suppress_filters", true);``.
205
  else if($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level".$n."_posts"] && (!$user || !current_user_can("access_s2member_level".$n)))
206
  {
207
  foreach(($_posts = preg_split("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level".$n."_posts"])) as $_p)
208
+ if(strpos($_p, "all-") === 0 && preg_match("/^all-(.+?)$/", $_p, $_m) /* Protecting `all-` of a specific Post Type? */)
209
+ if((is_array($_p_of_type = c_ws_plugin__s2member_utils_gets::get_all_post_ids($_m[1])) || (substr($_m[1], -1) === "s"
210
+ && is_array($_p_of_type = c_ws_plugin__s2member_utils_gets::get_all_post_ids(substr($_m[1], 0, -1)))))
211
+ && !empty($_p_of_type)) $_posts = array_merge /* Merge all Posts of this Post Type. */($_posts, $_p_of_type);
212
 
213
  $_posts = array_unique( /* Force integers. */c_ws_plugin__s2member_utils_arrays::force_integers($_posts));
214
 
293
  return; // For uniformity.
294
  }
295
  /**
296
+ * Filters WordPress navigation menu items.
297
  *
298
  * @package s2Member\Queries
299
  * @since 110912
377
  return apply_filters("_ws_plugin__s2member_is_admin_ajax_search", false, get_defined_vars());
378
  }
379
  /**
380
+ * Filters WordPress Page queries that use wp_list_pages()
381
  *
382
  * @package s2Member\Queries
383
  * @since 130617
includes/classes/register-access.inc.php CHANGED
@@ -100,7 +100,7 @@ if (!class_exists ("c_ws_plugin__s2member_register_access"))
100
  do_action ("ws_plugin__s2member_before_reg_cookies_ok", get_defined_vars ());
101
 
102
  if (isset ($_COOKIE["s2member_subscr_gateway"], $_COOKIE["s2member_subscr_id"], $_COOKIE["s2member_custom"], $_COOKIE["s2member_item_number"]))
103
- if (($subscr_gateway = c_ws_plugin__s2member_utils_encryption::decrypt ((string)$_COOKIE["s2member_subscr_gateway"])) && ($subscr_id = c_ws_plugin__s2member_utils_encryption::decrypt ((string)$_COOKIE["s2member_subscr_id"])) && preg_match ("/^" . preg_quote (preg_replace ("/\:([0-9]+)$/", "", $_SERVER["HTTP_HOST"]), "/") . "/i", ($custom = c_ws_plugin__s2member_utils_encryption::decrypt ((string)$_COOKIE["s2member_custom"]))) && preg_match ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["membership_item_number_w_level_regex"], ($item_number = c_ws_plugin__s2member_utils_encryption::decrypt ((string)$_COOKIE["s2member_item_number"]))) && !$wpdb->get_var ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = '" . $wpdb->prefix . "s2member_subscr_id' AND `meta_value` = '" . $wpdb->escape ($subscr_id) . "' LIMIT 1"))
104
  $reg_cookies_ok = $reg_cookies = array ("subscr_gateway" => $subscr_gateway, "subscr_id" => $subscr_id, "custom" => $custom, "item_number" => $item_number);
105
 
106
  return apply_filters ("ws_plugin__s2member_reg_cookies_ok", ((isset ($reg_cookies_ok) && $reg_cookies_ok && !empty ($reg_cookies)) ? $reg_cookies : false), get_defined_vars ());
100
  do_action ("ws_plugin__s2member_before_reg_cookies_ok", get_defined_vars ());
101
 
102
  if (isset ($_COOKIE["s2member_subscr_gateway"], $_COOKIE["s2member_subscr_id"], $_COOKIE["s2member_custom"], $_COOKIE["s2member_item_number"]))
103
+ if (($subscr_gateway = c_ws_plugin__s2member_utils_encryption::decrypt ((string)$_COOKIE["s2member_subscr_gateway"])) && ($subscr_id = c_ws_plugin__s2member_utils_encryption::decrypt ((string)$_COOKIE["s2member_subscr_id"])) && preg_match ("/^" . preg_quote (preg_replace ("/\:([0-9]+)$/", "", $_SERVER["HTTP_HOST"]), "/") . "/i", ($custom = c_ws_plugin__s2member_utils_encryption::decrypt ((string)$_COOKIE["s2member_custom"]))) && preg_match ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["membership_item_number_w_level_regex"], ($item_number = c_ws_plugin__s2member_utils_encryption::decrypt ((string)$_COOKIE["s2member_item_number"]))) && !$wpdb->get_var ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE `meta_key` = '" . $wpdb->prefix . "s2member_subscr_id' AND `meta_value` = '" . esc_sql($subscr_id) . "' LIMIT 1"))
104
  $reg_cookies_ok = $reg_cookies = array ("subscr_gateway" => $subscr_gateway, "subscr_id" => $subscr_id, "custom" => $custom, "item_number" => $item_number);
105
 
106
  return apply_filters ("ws_plugin__s2member_reg_cookies_ok", ((isset ($reg_cookies_ok) && $reg_cookies_ok && !empty ($reg_cookies)) ? $reg_cookies : false), get_defined_vars ());
includes/classes/registration-times.inc.php CHANGED
@@ -35,8 +35,8 @@ if (!class_exists ("c_ws_plugin__s2member_registration_times"))
35
  *
36
  * @attaches-to ``add_action("set_user_role");``
37
  *
38
- * @param int|str $user_id A numeric WordPress® User ID should be passed in by the Action Hook.
39
- * @param str $role A WordPress® Role ID/Name should be passed in by the Action Hook.
40
  * @return null
41
  */
42
  public static function synchronize_paid_reg_times ($user_id = FALSE, $role = FALSE)
@@ -61,7 +61,7 @@ if (!class_exists ("c_ws_plugin__s2member_registration_times"))
61
  * @package s2Member\Registrations
62
  * @since 3.5
63
  *
64
- * @param int|str $user_id Optional. A numeric WordPress® User ID. Defaults to the current User, if logged-in.
65
  * @return int A Unix timestamp, indicating Registration Time, else `0` on failure.
66
  */
67
  public static function registration_time ($user_id = FALSE)
@@ -86,7 +86,7 @@ if (!class_exists ("c_ws_plugin__s2member_registration_times"))
86
  * @since 3.5
87
  *
88
  * @param int|str $level Optional. Defaults to the first/initial Paid Registration Time, regardless of Level#.
89
- * @param int|str $user_id Optional. A numeric WordPress® User ID. Defaults to the current User, if logged-in.
90
  * @return int A Unix timestamp, indicating Paid Registration Time, else `0` on failure.
91
  */
92
  public static function paid_registration_time ($level = FALSE, $user_id = FALSE)
35
  *
36
  * @attaches-to ``add_action("set_user_role");``
37
  *
38
+ * @param int|str $user_id A numeric WordPress User ID should be passed in by the Action Hook.
39
+ * @param str $role A WordPress Role ID/Name should be passed in by the Action Hook.
40
  * @return null
41
  */
42
  public static function synchronize_paid_reg_times ($user_id = FALSE, $role = FALSE)
61
  * @package s2Member\Registrations
62
  * @since 3.5
63
  *
64
+ * @param int|str $user_id Optional. A numeric WordPress User ID. Defaults to the current User, if logged-in.
65
  * @return int A Unix timestamp, indicating Registration Time, else `0` on failure.
66
  */
67
  public static function registration_time ($user_id = FALSE)
86
  * @since 3.5
87
  *
88
  * @param int|str $level Optional. Defaults to the first/initial Paid Registration Time, regardless of Level#.
89
+ * @param int|str $user_id Optional. A numeric WordPress User ID. Defaults to the current User, if logged-in.
90
  * @return int A Unix timestamp, indicating Paid Registration Time, else `0` on failure.
91
  */
92
  public static function paid_registration_time ($level = FALSE, $user_id = FALSE)
includes/classes/registrations.inc.php CHANGED
@@ -28,9 +28,9 @@ if (!class_exists ("c_ws_plugin__s2member_registrations"))
28
  class c_ws_plugin__s2member_registrations
29
  {
30
  /**
31
- * Filters WordPress® randomly generated Passwords.
32
  *
33
- * Also captures Passwords generated by WordPress®
34
  * *(with a global var)*, for internal use.
35
  *
36
  * @package s2Member\Registrations
@@ -227,7 +227,7 @@ if (!class_exists ("c_ws_plugin__s2member_registrations"))
227
  *
228
  * @attaches-to ``add_action("wpmu_activate_user");``
229
  *
230
- * @param int|str $user_id A numeric WordPress® User ID.
231
  * @param str $password Plain text Password should be passed through by the Action Hook.
232
  * @param array $meta Expects an array of ``$meta`` details, passed through by the Action Hook.
233
  * @return null
@@ -266,8 +266,8 @@ if (!class_exists ("c_ws_plugin__s2member_registrations"))
266
  *
267
  * @attaches-to ``add_action("wpmu_activate_blog");``
268
  *
269
- * @param int|str $blog_id A numeric WordPress® Blog ID.
270
- * @param int|str $user_id A numeric WordPress® User ID.
271
  * @param str $password Plain text Password should be passed through by the Action Hook.
272
  * @param str $title The title that a User chose during signup; for their new Blog on the Network.
273
  * @param array $meta Expects an array of ``$meta`` details, passed through by the Action Hook.
@@ -357,7 +357,7 @@ if (!class_exists ("c_ws_plugin__s2member_registrations"))
357
  * @param str $user_login Expects the User's Username.
358
  * @param str $user_email Expects the User's Email Address.
359
  * @param str $user_pass Expects the User's plain text Password.
360
- * @param int|str $user_id Optional. A numeric WordPress® User ID.
361
  * If unspecified, a lookup is performed with ``$user_login`` and ``$user_email``.
362
  * @return int|false Returns numeric ``$user_id`` on success, else false on failure.
363
  */
@@ -398,7 +398,7 @@ if (!class_exists ("c_ws_plugin__s2member_registrations"))
398
  *
399
  * @attaches-to ``add_action("user_register");``
400
  *
401
- * @param int|str $user_id A numeric WordPress® User ID.
402
  * @param str $password Optional in most cases. A User's plain text Password. If unspecified, attempts are made to collect the plain text Password from other sources.
403
  * @param array $meta Optional in most cases. Defaults to false. An array of meta data for a User/Member.
404
  * @return null No return value. Returns `null` in possible every scenario.
@@ -423,7 +423,7 @@ if (!class_exists ("c_ws_plugin__s2member_registrations"))
423
  $_p = /* Grab global ``$_POST`` array here, if it's possible to do so. */ (isset ($_POST)) ? $_POST : null;
424
  $rvs = (isset ($GLOBALS["ws_plugin__s2member_registration_vars"])) ? $GLOBALS["ws_plugin__s2member_registration_vars"] : null;
425
 
426
- if (!$processed /* Process only once. Safeguard this routine against duplicate processing via plugins (or even WordPress® itself). */)
427
 
428
  if ( /* We MUST have at least ONE of these three arrays. Any of these will do in most cases. */is_array ($_p) || is_array ($meta) || is_array ($rvs))
429
 
28
  class c_ws_plugin__s2member_registrations
29
  {
30
  /**
31
+ * Filters WordPress randomly generated Passwords.
32
  *
33
+ * Also captures Passwords generated by WordPress
34
  * *(with a global var)*, for internal use.
35
  *
36
  * @package s2Member\Registrations
227
  *
228
  * @attaches-to ``add_action("wpmu_activate_user");``
229
  *
230
+ * @param int|str $user_id A numeric WordPress User ID.
231
  * @param str $password Plain text Password should be passed through by the Action Hook.
232
  * @param array $meta Expects an array of ``$meta`` details, passed through by the Action Hook.
233
  * @return null
266
  *
267
  * @attaches-to ``add_action("wpmu_activate_blog");``
268
  *
269
+ * @param int|str $blog_id A numeric WordPress Blog ID.
270
+ * @param int|str $user_id A numeric WordPress User ID.
271
  * @param str $password Plain text Password should be passed through by the Action Hook.
272
  * @param str $title The title that a User chose during signup; for their new Blog on the Network.
273
  * @param array $meta Expects an array of ``$meta`` details, passed through by the Action Hook.
357
  * @param str $user_login Expects the User's Username.
358
  * @param str $user_email Expects the User's Email Address.
359
  * @param str $user_pass Expects the User's plain text Password.
360
+ * @param int|str $user_id Optional. A numeric WordPress User ID.
361
  * If unspecified, a lookup is performed with ``$user_login`` and ``$user_email``.
362
  * @return int|false Returns numeric ``$user_id`` on success, else false on failure.
363
  */
398
  *
399
  * @attaches-to ``add_action("user_register");``
400
  *
401
+ * @param int|str $user_id A numeric WordPress User ID.
402
  * @param str $password Optional in most cases. A User's plain text Password. If unspecified, attempts are made to collect the plain text Password from other sources.
403
  * @param array $meta Optional in most cases. Defaults to false. An array of meta data for a User/Member.
404
  * @return null No return value. Returns `null` in possible every scenario.
423
  $_p = /* Grab global ``$_POST`` array here, if it's possible to do so. */ (isset ($_POST)) ? $_POST : null;
424
  $rvs = (isset ($GLOBALS["ws_plugin__s2member_registration_vars"])) ? $GLOBALS["ws_plugin__s2member_registration_vars"] : null;
425
 
426
+ if (!$processed /* Process only once. Safeguard this routine against duplicate processing via plugins (or even WordPress itself). */)
427
 
428
  if ( /* We MUST have at least ONE of these three arrays. Any of these will do in most cases. */is_array ($_p) || is_array ($meta) || is_array ($rvs))
429
 
includes/classes/roles-caps.inc.php CHANGED
@@ -43,13 +43,13 @@ if(!class_exists("c_ws_plugin__s2member_roles_caps"))
43
  {
44
  c_ws_plugin__s2member_roles_caps::unlink_roles();
45
 
46
- if(function_exists("bbp_get_dynamic_roles") /* bbPress® v2.2+ integration. */)
47
  {
48
  foreach(bbp_get_caps_for_role(bbp_get_participant_role()) as $bbp_participant_cap => $bbp_participant_cap_is)
49
  if($bbp_participant_cap_is /* Is this capability enabled? */)
50
  $bbp_participant_caps[$bbp_participant_cap] = true;
51
  }
52
- else if(function_exists("bbp_get_caps_for_role") /* bbPress® < v2.2 integration. */)
53
  {
54
  foreach(bbp_get_caps_for_role(bbp_get_participant_role()) as $bbp_participant_cap)
55
  $bbp_participant_caps[$bbp_participant_cap] = true;
@@ -89,7 +89,7 @@ if(!class_exists("c_ws_plugin__s2member_roles_caps"))
89
 
90
  $full_access_roles = array("administrator", "editor", "author", "contributor");
91
 
92
- if(function_exists("bbp_get_caps_for_role") && !function_exists("bbp_get_dynamic_roles") /* bbPress® < v2.2 integration. */)
93
  $full_access_roles = array_merge($full_access_roles, (array)bbp_get_moderator_role());
94
 
95
  foreach($full_access_roles as $role)
@@ -105,7 +105,7 @@ if(!class_exists("c_ws_plugin__s2member_roles_caps"))
105
  return /* Return for uniformity. */;
106
  }
107
  /**
108
- * Adds support for bbPress® v2.2+ dynamic roles.
109
  *
110
  * @package s2Member\Roles_Caps
111
  * @since 112512
@@ -152,7 +152,7 @@ if(!class_exists("c_ws_plugin__s2member_roles_caps"))
152
 
153
  $full_access_roles = array("administrator", "editor", "author", "contributor");
154
 
155
- if(function_exists("bbp_get_caps_for_role") && !function_exists("bbp_get_dynamic_roles") /* bbPress® < v2.2 integration. */)
156
  $full_access_roles = array_merge($full_access_roles, (array)bbp_get_moderator_role());
157
 
158
  foreach($full_access_roles as $role)
43
  {
44
  c_ws_plugin__s2member_roles_caps::unlink_roles();
45
 
46
+ if(function_exists("bbp_get_dynamic_roles") /* bbPress v2.2+ integration. */)
47
  {
48
  foreach(bbp_get_caps_for_role(bbp_get_participant_role()) as $bbp_participant_cap => $bbp_participant_cap_is)
49
  if($bbp_participant_cap_is /* Is this capability enabled? */)
50
  $bbp_participant_caps[$bbp_participant_cap] = true;
51
  }
52
+ else if(function_exists("bbp_get_caps_for_role") /* bbPress < v2.2 integration. */)
53
  {
54
  foreach(bbp_get_caps_for_role(bbp_get_participant_role()) as $bbp_participant_cap)
55
  $bbp_participant_caps[$bbp_participant_cap] = true;
89
 
90
  $full_access_roles = array("administrator", "editor", "author", "contributor");
91
 
92
+ if(function_exists("bbp_get_caps_for_role") && !function_exists("bbp_get_dynamic_roles") /* bbPress < v2.2 integration. */)
93
  $full_access_roles = array_merge($full_access_roles, (array)bbp_get_moderator_role());
94
 
95
  foreach($full_access_roles as $role)
105
  return /* Return for uniformity. */;
106
  }
107
  /**
108
+ * Adds support for bbPress v2.2+ dynamic roles.
109
  *
110
  * @package s2Member\Roles_Caps
111
  * @since 112512
152
 
153
  $full_access_roles = array("administrator", "editor", "author", "contributor");
154
 
155
+ if(function_exists("bbp_get_caps_for_role") && !function_exists("bbp_get_dynamic_roles") /* bbPress < v2.2 integration. */)
156
  $full_access_roles = array_merge($full_access_roles, (array)bbp_get_moderator_role());
157
 
158
  foreach($full_access_roles as $role)
includes/classes/ruris-sp.inc.php CHANGED
@@ -47,7 +47,7 @@ if (!class_exists ("c_ws_plugin__s2member_ruris_sp"))
47
 
48
  if (!$excluded && !empty ($uri) && is_string ($uri) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
49
  {
50
- if (!c_ws_plugin__s2member_systematics_sp::is_wp_systematic_use_specific_page (null, $uri)) // Do NOT touch WordPress® Systematics.
51
  {
52
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
53
 
47
 
48
  if (!$excluded && !empty ($uri) && is_string ($uri) && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"])
49
  {
50
+ if (!c_ws_plugin__s2member_systematics_sp::is_wp_systematic_use_specific_page (null, $uri)) // Do NOT touch WordPress Systematics.
51
  {
52
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
53
 
includes/classes/ruris.inc.php CHANGED
@@ -43,7 +43,7 @@ if (!class_exists ("c_ws_plugin__s2member_ruris"))
43
 
44
  if (!$excluded && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]) // Has it been excluded?
45
  {
46
- if (!c_ws_plugin__s2member_systematics::is_wp_systematic_use_page ()) // Do NOT touch WordPress® Systematics. This excludes all WordPress® Systematics.
47
  {
48
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
49
 
43
 
44
  if (!$excluded && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_options_page"]) // Has it been excluded?
45
  {
46
+ if (!c_ws_plugin__s2member_systematics::is_wp_systematic_use_page ()) // Do NOT touch WordPress Systematics. This excludes all WordPress Systematics.
47
  {
48
  $user = (is_user_logged_in () && is_object ($user = wp_get_current_user ()) && !empty ($user->ID)) ? $user : false; // Current User's object.
49
 
includes/classes/sc-paypal-button-e.inc.php CHANGED
@@ -28,17 +28,17 @@ if (!class_exists ("c_ws_plugin__s2member_sc_paypal_button_e"))
28
  class c_ws_plugin__s2member_sc_paypal_button_e
29
  {
30
  /**
31
- * Handles PayPal® Button encryption.
32
  *
33
- * This uses the PayPal® API. s2Member will NOT attempt to encrypt Buttons until there is at least a Business Email Address and API Username configured.
34
- * s2Member also maintains a log of communication with the PayPal® API. If logging is enabled, check: `/wp-content/plugins/s2member-logs/paypal-api.log`.
35
  *
36
  * @package s2Member\PayPal
37
  * @since 3.5
38
  *
39
- * @param str $code The PayPal® Button Code before encryption.
40
  * @param array $vars An array of defined variables in the scope of the calling Filter.
41
- * @return str The Resulting PayPal® Button Code *(possibly encrypted, depending on configuration)*.
42
  */
43
  public static function sc_paypal_button_encryption ($code = FALSE, $vars = FALSE)
44
  {
@@ -59,11 +59,11 @@ if (!class_exists ("c_ws_plugin__s2member_sc_paypal_button_e"))
59
  {
60
  $paypal = array ("METHOD" => "BMCreateButton", "BUTTONCODE" => "ENCRYPTED", "BUTTONTYPE" => (($attr["sp"] || $attr["rr"] === "BN") ? "BUYNOW" : "SUBSCRIBE"));
61
 
62
- $i = 0; // Initialize incremental variable counter. PayPal® wants these numbered using L_BUTTONVAR{n}; where {n} starts at zero.
63
  foreach ($inputs as $input => $value) // Now run through each of the input variables that we parsed from the Full Button Code
64
  if (!preg_match ("/^cmd$/i", $input)) // Don't include the `cmd` var; it will produce major errors in the API response.
65
  {
66
- // The PayPal® API method `BMCreateButton` expects (amount|a1|a3) to include 2 decimal places.
67
  if (preg_match ("/^(amount|a1|a3)$/i", $input))
68
  $value = number_format ($value, 2, ".", "");
69
 
@@ -72,23 +72,23 @@ if (!class_exists ("c_ws_plugin__s2member_sc_paypal_button_e"))
72
  }
73
 
74
  if (($paypal = c_ws_plugin__s2member_paypal_utilities::paypal_api_response ($paypal)) && empty ($paypal["__error"]) && !empty ($paypal["WEBSITECODE"]) && ($code = $paypal["WEBSITECODE"]))
75
- // Only proceed if we DID get a valid response from the PayPal® API. This works as a nice fallback; just in case the API connection fails.
76
  {
77
  $default_image = "https://www.paypal.com/" . (($attr["lang"]) ? $attr["lang"] : _x ("en_US", "s2member-front paypal-button-lang-code", "s2member")) . "/i/btn/btn_xpressCheckout.gif";
78
 
79
- $code = preg_replace ("/\<img[^\>]+\>/i", "", $code); // Remove 1x1 pixel tracking image that PayPal® sticks in there.
80
  $code = preg_replace ("/(\<input)([^\>]+)(\>)/ie", "'\\1'.rtrim(stripslashes('\\2'),'/').' /\\3'", $code); // Use XHTML!
81
 
82
  $code = ($attr["image"] && $attr["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($attr["image"])) . '"', $code) : preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($default_image)) . '"', $code);
83
 
84
- $code = ($attr["output"] === "anchor") ? '<a href="' . esc_attr (c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code)) . '"><img src="' . esc_attr (($attr["image"] && $attr["image"] !== "default") ? $attr["image"] : $default_image) . '" style="width:auto; height:auto; border:0;" alt="PayPal®" /></a>' : $code;
85
  $code = ($attr["output"] === "url") ? c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code) : $code;
86
 
87
  ($cache && $transient) ? set_transient ($transient, $code, apply_filters ("ws_plugin__s2member_sc_paypal_button_encryption_cache_exp_time", 3600, get_defined_vars ())) : null; // Caching?
88
  }
89
  }
90
  }
91
- // No WordPress® Filters apply here.
92
  // Instead, use: `ws_plugin__s2member_sc_paypal_button`.
93
  return $code; // Button Code. Possibly w/ API encryption now.
94
  }
28
  class c_ws_plugin__s2member_sc_paypal_button_e
29
  {
30
  /**
31
+ * Handles PayPal Button encryption.
32
  *
33
+ * This uses the PayPal API. s2Member will NOT attempt to encrypt Buttons until there is at least a Business Email Address and API Username configured.
34
+ * s2Member also maintains a log of communication with the PayPal API. If logging is enabled, check: `/wp-content/plugins/s2member-logs/paypal-api.log`.
35
  *
36
  * @package s2Member\PayPal
37
  * @since 3.5
38
  *
39
+ * @param str $code The PayPal Button Code before encryption.
40
  * @param array $vars An array of defined variables in the scope of the calling Filter.
41
+ * @return str The Resulting PayPal Button Code *(possibly encrypted, depending on configuration)*.
42
  */
43
  public static function sc_paypal_button_encryption ($code = FALSE, $vars = FALSE)
44
  {
59
  {
60
  $paypal = array ("METHOD" => "BMCreateButton", "BUTTONCODE" => "ENCRYPTED", "BUTTONTYPE" => (($attr["sp"] || $attr["rr"] === "BN") ? "BUYNOW" : "SUBSCRIBE"));
61
 
62
+ $i = 0; // Initialize incremental variable counter. PayPal wants these numbered using L_BUTTONVAR{n}; where {n} starts at zero.
63
  foreach ($inputs as $input => $value) // Now run through each of the input variables that we parsed from the Full Button Code
64
  if (!preg_match ("/^cmd$/i", $input)) // Don't include the `cmd` var; it will produce major errors in the API response.
65
  {
66
+ // The PayPal API method `BMCreateButton` expects (amount|a1|a3) to include 2 decimal places.
67
  if (preg_match ("/^(amount|a1|a3)$/i", $input))
68
  $value = number_format ($value, 2, ".", "");
69
 
72
  }
73
 
74
  if (($paypal = c_ws_plugin__s2member_paypal_utilities::paypal_api_response ($paypal)) && empty ($paypal["__error"]) && !empty ($paypal["WEBSITECODE"]) && ($code = $paypal["WEBSITECODE"]))
75
+ // Only proceed if we DID get a valid response from the PayPal API. This works as a nice fallback; just in case the API connection fails.
76
  {
77
  $default_image = "https://www.paypal.com/" . (($attr["lang"]) ? $attr["lang"] : _x ("en_US", "s2member-front paypal-button-lang-code", "s2member")) . "/i/btn/btn_xpressCheckout.gif";
78
 
79
+ $code = preg_replace ("/\<img[^\>]+\>/i", "", $code); // Remove 1x1 pixel tracking image that PayPal sticks in there.
80
  $code = preg_replace ("/(\<input)([^\>]+)(\>)/ie", "'\\1'.rtrim(stripslashes('\\2'),'/').' /\\3'", $code); // Use XHTML!
81
 
82
  $code = ($attr["image"] && $attr["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($attr["image"])) . '"', $code) : preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($default_image)) . '"', $code);
83
 
84
+ $code = ($attr["output"] === "anchor") ? '<a href="' . esc_attr (c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code)) . '"><img src="' . esc_attr (($attr["image"] && $attr["image"] !== "default") ? $attr["image"] : $default_image) . '" style="width:auto; height:auto; border:0;" alt="PayPal" /></a>' : $code;
85
  $code = ($attr["output"] === "url") ? c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code) : $code;
86
 
87
  ($cache && $transient) ? set_transient ($transient, $code, apply_filters ("ws_plugin__s2member_sc_paypal_button_encryption_cache_exp_time", 3600, get_defined_vars ())) : null; // Caching?
88
  }
89
  }
90
  }
91
+ // No WordPress Filters apply here.
92
  // Instead, use: `ws_plugin__s2member_sc_paypal_button`.
93
  return $code; // Button Code. Possibly w/ API encryption now.
94
  }
includes/classes/sc-paypal-button-in.inc.php CHANGED
@@ -38,7 +38,7 @@ if (!class_exists ("c_ws_plugin__s2member_sc_paypal_button_in"))
38
  * @param array $attr An array of Attributes.
39
  * @param str $content Content inside the Shortcode.
40
  * @param str $shortcode The actual Shortcode name itself.
41
- * @return str The resulting PayPal® Button Code.
42
  */
43
  public static function sc_paypal_button ($attr = FALSE, $content = FALSE, $shortcode = FALSE)
44
  {
@@ -95,7 +95,7 @@ if (!class_exists ("c_ws_plugin__s2member_sc_paypal_button_in"))
95
  $default_image = "https://www.paypal.com/" . (($attr["lang"]) ? $attr["lang"] : _x ("en_US", "s2member-front paypal-button-lang-code", "s2member")) . "/i/btn/btn_xpressCheckout.gif";
96
 
97
  $paypal_on0_input_value = ($referencing = c_ws_plugin__s2member_utils_users::get_user_subscr_or_wp_id ()) ? "Referencing Customer ID" : "Originating Domain";
98
- $paypal_os0_input_value = /* Current User's Paid Subscr. ID, or WP® User ID, or domain. */ ($referencing) ? $referencing : $_SERVER["HTTP_HOST"];
99
 
100
  $paypal_on1_input_value = /* Identifies the Customer's IP Address for tracking purposes. */ "Customer IP Address";
101
  $paypal_os1_input_value = /* Current User's IP Address for tracking purposes. */ $_SERVER["REMOTE_ADDR"];
@@ -137,7 +137,7 @@ if (!class_exists ("c_ws_plugin__s2member_sc_paypal_button_in"))
137
 
138
  $code = $_code = ($attr["image"] && $attr["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($attr["image"])) . '"', $code) : preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($default_image)) . '"', $code);
139
 
140
- $code = ($attr["output"] === "anchor") ? '<a href="' . esc_attr (c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code)) . '"><img src="' . esc_attr (($attr["image"] && $attr["image"] !== "default") ? $attr["image"] : $default_image) . '" style="width:auto; height:auto; border:0;" alt="PayPal®" /></a>' : $code;
141
  $code = ($attr["output"] === "url") ? c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code) : $code;
142
 
143
  foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
@@ -149,7 +149,7 @@ if (!class_exists ("c_ws_plugin__s2member_sc_paypal_button_in"))
149
  $default_image = "https://www.paypal.com/" . (($attr["lang"]) ? $attr["lang"] : _x ("en_US", "s2member-front paypal-button-lang-code", "s2member")) . "/i/btn/btn_xpressCheckout.gif";
150
 
151
  $paypal_on0_input_value = ($referencing = c_ws_plugin__s2member_utils_users::get_user_subscr_or_wp_id ()) ? "Referencing Customer ID" : "Originating Domain";
152
- $paypal_os0_input_value = /* Current User's Paid Subscr. ID, or WP® User ID, or domain. */ ($referencing) ? $referencing : $_SERVER["HTTP_HOST"];
153
 
154
  $paypal_on1_input_value = /* Identifies the Customer's IP Address for tracking purposes. */ "Customer IP Address";
155
  $paypal_os1_input_value = /* Current User's IP Address for tracking purposes. */ $_SERVER["REMOTE_ADDR"];
@@ -192,7 +192,7 @@ if (!class_exists ("c_ws_plugin__s2member_sc_paypal_button_in"))
192
 
193
  $code = $_code = ($attr["image"] && $attr["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($attr["image"])) . '"', $code) : preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($default_image)) . '"', $code);
194
 
195
- $code = ($attr["output"] === "anchor") ? '<a href="' . esc_attr (c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code)) . '"><img src="' . esc_attr (($attr["image"] && $attr["image"] !== "default") ? $attr["image"] : $default_image) . '" style="width:auto; height:auto; border:0;" alt="PayPal®" /></a>' : $code;
196
  $code = ($attr["output"] === "url") ? c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code) : $code;
197
 
198
  foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
@@ -204,7 +204,7 @@ if (!class_exists ("c_ws_plugin__s2member_sc_paypal_button_in"))
204
  $default_image = "https://www.paypal.com/" . (($attr["lang"]) ? $attr["lang"] : _x ("en_US", "s2member-front paypal-button-lang-code", "s2member")) . "/i/btn/btn_xpressCheckout.gif";
205
 
206
  $paypal_on0_input_value = ($referencing = c_ws_plugin__s2member_utils_users::get_user_subscr_or_wp_id ()) ? "Referencing Customer ID" : "Originating Domain";
207
- $paypal_os0_input_value = /* Current User's Paid Subscr. ID, or WP® User ID, or domain. */ ($referencing) ? $referencing : $_SERVER["HTTP_HOST"];
208
 
209
  $paypal_on1_input_value = /* Identifies the Customer's IP Address for tracking purposes. */ "Customer IP Address";
210
  $paypal_os1_input_value = /* Current User's IP Address for tracking purposes. */ $_SERVER["REMOTE_ADDR"];
@@ -274,7 +274,7 @@ if (!class_exists ("c_ws_plugin__s2member_sc_paypal_button_in"))
274
 
275
  $code = $_code = ($attr["image"] && $attr["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($attr["image"])) . '"', $code) : preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($default_image)) . '"', $code);
276
 
277
- $code = ($attr["output"] === "anchor") ? '<a href="' . esc_attr (c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code)) . '"><img src="' . esc_attr (($attr["image"] && $attr["image"] !== "default") ? $attr["image"] : $default_image) . '" style="width:auto; height:auto; border:0;" alt="PayPal®" /></a>' : $code;
278
  $code = ($attr["output"] === "url") ? c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code) : $code;
279
 
280
  foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
38
  * @param array $attr An array of Attributes.
39
  * @param str $content Content inside the Shortcode.
40
  * @param str $shortcode The actual Shortcode name itself.
41
+ * @return str The resulting PayPal Button Code.
42
  */
43
  public static function sc_paypal_button ($attr = FALSE, $content = FALSE, $shortcode = FALSE)
44
  {
95
  $default_image = "https://www.paypal.com/" . (($attr["lang"]) ? $attr["lang"] : _x ("en_US", "s2member-front paypal-button-lang-code", "s2member")) . "/i/btn/btn_xpressCheckout.gif";
96
 
97
  $paypal_on0_input_value = ($referencing = c_ws_plugin__s2member_utils_users::get_user_subscr_or_wp_id ()) ? "Referencing Customer ID" : "Originating Domain";
98
+ $paypal_os0_input_value = /* Current User's Paid Subscr. ID, or WP User ID, or domain. */ ($referencing) ? $referencing : $_SERVER["HTTP_HOST"];
99
 
100
  $paypal_on1_input_value = /* Identifies the Customer's IP Address for tracking purposes. */ "Customer IP Address";
101
  $paypal_os1_input_value = /* Current User's IP Address for tracking purposes. */ $_SERVER["REMOTE_ADDR"];
137
 
138
  $code = $_code = ($attr["image"] && $attr["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($attr["image"])) . '"', $code) : preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($default_image)) . '"', $code);
139
 
140
+ $code = ($attr["output"] === "anchor") ? '<a href="' . esc_attr (c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code)) . '"><img src="' . esc_attr (($attr["image"] && $attr["image"] !== "default") ? $attr["image"] : $default_image) . '" style="width:auto; height:auto; border:0;" alt="PayPal" /></a>' : $code;
141
  $code = ($attr["output"] === "url") ? c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code) : $code;
142
 
143
  foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
149
  $default_image = "https://www.paypal.com/" . (($attr["lang"]) ? $attr["lang"] : _x ("en_US", "s2member-front paypal-button-lang-code", "s2member")) . "/i/btn/btn_xpressCheckout.gif";
150
 
151
  $paypal_on0_input_value = ($referencing = c_ws_plugin__s2member_utils_users::get_user_subscr_or_wp_id ()) ? "Referencing Customer ID" : "Originating Domain";
152
+ $paypal_os0_input_value = /* Current User's Paid Subscr. ID, or WP User ID, or domain. */ ($referencing) ? $referencing : $_SERVER["HTTP_HOST"];
153
 
154
  $paypal_on1_input_value = /* Identifies the Customer's IP Address for tracking purposes. */ "Customer IP Address";
155
  $paypal_os1_input_value = /* Current User's IP Address for tracking purposes. */ $_SERVER["REMOTE_ADDR"];
192
 
193
  $code = $_code = ($attr["image"] && $attr["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($attr["image"])) . '"', $code) : preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($default_image)) . '"', $code);
194
 
195
+ $code = ($attr["output"] === "anchor") ? '<a href="' . esc_attr (c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code)) . '"><img src="' . esc_attr (($attr["image"] && $attr["image"] !== "default") ? $attr["image"] : $default_image) . '" style="width:auto; height:auto; border:0;" alt="PayPal" /></a>' : $code;
196
  $code = ($attr["output"] === "url") ? c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code) : $code;
197
 
198
  foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
204
  $default_image = "https://www.paypal.com/" . (($attr["lang"]) ? $attr["lang"] : _x ("en_US", "s2member-front paypal-button-lang-code", "s2member")) . "/i/btn/btn_xpressCheckout.gif";
205
 
206
  $paypal_on0_input_value = ($referencing = c_ws_plugin__s2member_utils_users::get_user_subscr_or_wp_id ()) ? "Referencing Customer ID" : "Originating Domain";
207
+ $paypal_os0_input_value = /* Current User's Paid Subscr. ID, or WP User ID, or domain. */ ($referencing) ? $referencing : $_SERVER["HTTP_HOST"];
208
 
209
  $paypal_on1_input_value = /* Identifies the Customer's IP Address for tracking purposes. */ "Customer IP Address";
210
  $paypal_os1_input_value = /* Current User's IP Address for tracking purposes. */ $_SERVER["REMOTE_ADDR"];
274
 
275
  $code = $_code = ($attr["image"] && $attr["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($attr["image"])) . '"', $code) : preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($default_image)) . '"', $code);
276
 
277
+ $code = ($attr["output"] === "anchor") ? '<a href="' . esc_attr (c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code)) . '"><img src="' . esc_attr (($attr["image"] && $attr["image"] !== "default") ? $attr["image"] : $default_image) . '" style="width:auto; height:auto; border:0;" alt="PayPal" /></a>' : $code;
278
  $code = ($attr["output"] === "url") ? c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code) : $code;
279
 
280
  foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
includes/classes/security.inc.php CHANGED
@@ -28,7 +28,7 @@ if (!class_exists ("c_ws_plugin__s2member_security"))
28
  class c_ws_plugin__s2member_security
29
  {
30
  /**
31
- * s2Member's Security Gate (protects WordPress® content).
32
  *
33
  * @package s2Member\Security
34
  * @since 3.5
@@ -61,7 +61,7 @@ if (!class_exists ("c_ws_plugin__s2member_security"))
61
  return /* Return for uniformity. */;
62
  }
63
  /**
64
- * s2Member's Security Gate (protects WordPress® queries).
65
  *
66
  * @package s2Member\Security
67
  * @since 3.5
@@ -69,7 +69,7 @@ if (!class_exists ("c_ws_plugin__s2member_security"))
69
  * @attaches-to ``add_action("pre_get_posts");``
70
  *
71
  * @param obj $wp_query Global ``$wp_query``, by reference.
72
- * @return null May filter WordPress® queries, by hiding protected content which is NOT available to the current User/Member.
73
  */
74
  public static function security_gate_query (&$wp_query = FALSE) // s2Member's Security Gate.
75
  {
28
  class c_ws_plugin__s2member_security
29
  {
30
  /**
31
+ * s2Member's Security Gate (protects WordPress content).
32
  *
33
  * @package s2Member\Security
34
  * @since 3.5
61
  return /* Return for uniformity. */;
62
  }
63
  /**
64
+ * s2Member's Security Gate (protects WordPress queries).
65
  *
66
  * @package s2Member\Security
67
  * @since 3.5
69
  * @attaches-to ``add_action("pre_get_posts");``
70
  *
71
  * @param obj $wp_query Global ``$wp_query``, by reference.
72
+ * @return null May filter WordPress queries, by hiding protected content which is NOT available to the current User/Member.
73
  */
74
  public static function security_gate_query (&$wp_query = FALSE) // s2Member's Security Gate.
75
  {
includes/classes/sp-access.inc.php CHANGED
@@ -88,7 +88,7 @@ if (!class_exists ("c_ws_plugin__s2member_sp_access"))
88
  * @package s2Member\SP_Access
89
  * @since 3.5
90
  *
91
- * @param int|str $sp_id Numeric Post/Page ID in WordPress®.
92
  * @param bool $read_only Optional. Defaults to false. If ``$read_only = true``,
93
  * no session cookies are set, no IP Restrictions are checked, and script execution is not exited on Link failure.
94
  * In other words, with ``$read_only = true``, this function will simply return true or false.
88
  * @package s2Member\SP_Access
89
  * @since 3.5
90
  *
91
+ * @param int|str $sp_id Numeric Post/Page ID in WordPress.
92
  * @param bool $read_only Optional. Defaults to false. If ``$read_only = true``,
93
  * no session cookies are set, no IP Restrictions are checked, and script execution is not exited on Link failure.
94
  * In other words, with ``$read_only = true``, this function will simply return true or false.
includes/classes/ssl.inc.php CHANGED
@@ -50,7 +50,7 @@ if (!class_exists ("c_ws_plugin__s2member_ssl"))
50
  do_action ("ws_plugin__s2member_before_check_force_ssl", get_defined_vars ());
51
 
52
  if (!$forced) // Only force SSL here once. We definitely do NOT need to run this particular routine more than ONE time.
53
- if (!c_ws_plugin__s2member_systematics::is_wp_systematic_use_page () /* NOT on WordPress® Systematics. */)
54
  {
55
  $s2_ssl_gv = apply_filters ("ws_plugin__s2member_check_force_ssl_get_var_name", "s2-ssl", get_defined_vars ());
56
  $_g_s2_ssl = (isset ($_GET[$s2_ssl_gv]) && (!strlen ($_GET[$s2_ssl_gv]) || !preg_match ("/^(0|no|off|false)$/i", $_GET[$s2_ssl_gv]))) ? ((!strlen ($_GET[$s2_ssl_gv])) ? true : $_GET[$s2_ssl_gv]) : false;
50
  do_action ("ws_plugin__s2member_before_check_force_ssl", get_defined_vars ());
51
 
52
  if (!$forced) // Only force SSL here once. We definitely do NOT need to run this particular routine more than ONE time.
53
+ if (!c_ws_plugin__s2member_systematics::is_wp_systematic_use_page () /* NOT on WordPress Systematics. */)
54
  {
55
  $s2_ssl_gv = apply_filters ("ws_plugin__s2member_check_force_ssl_get_var_name", "s2-ssl", get_defined_vars ());
56
  $_g_s2_ssl = (isset ($_GET[$s2_ssl_gv]) && (!strlen ($_GET[$s2_ssl_gv]) || !preg_match ("/^(0|no|off|false)$/i", $_GET[$s2_ssl_gv]))) ? ((!strlen ($_GET[$s2_ssl_gv])) ? true : $_GET[$s2_ssl_gv]) : false;
includes/classes/systematics-sp.inc.php CHANGED
@@ -28,14 +28,14 @@ if (!class_exists ("c_ws_plugin__s2member_systematics_sp"))
28
  class c_ws_plugin__s2member_systematics_sp
29
  {
30
  /**
31
- * Determines if a specific Post/Page ID, or URI, is s2Member® Systematic.
32
  *
33
  * @package s2Member\Systematics
34
  * @since 111115
35
  *
36
- * @param int|str $singular_id Optional. A numeric Post/Page ID in WordPress®.
37
  * @param str $uri Optional. A request URI to test against.
38
- * @return bool True if s2Member® Systematic, else false.
39
  */
40
  public static function is_s2_systematic_use_specific_page ($singular_id = FALSE, $uri = FALSE)
41
  {
@@ -46,25 +46,25 @@ if (!class_exists ("c_ws_plugin__s2member_systematics_sp"))
46
  {
47
  return ($is_s2_systematic = apply_filters ("ws_plugin__s2member_is_s2_systematic_use_specific_page", true, get_defined_vars ()));
48
  }
49
- else // Otherwise, we return false (i.e. it's NOT an s2Member® Systematic Use Page).
50
  return ($is_s2_systematic = apply_filters ("ws_plugin__s2member_is_s2_systematic_use_specific_page", false, get_defined_vars ()));
51
  }
52
  /**
53
- * Determines if a specific Post/Page ID, or URI, is WordPress® Systematic.
54
  *
55
  * @package s2Member\Systematics
56
  * @since 111002
57
  *
58
- * @param int|str $singular_id Optional. A numeric Post/Page ID in WordPress®.
59
  * @param str $uri Optional. A request URI to test against.
60
- * @return bool True if WordPress® Systematic, else false.
61
  */
62
  public static function is_wp_systematic_use_specific_page ($singular_id = FALSE, $uri = FALSE)
63
  {
64
  $singular_id = ($singular_id && is_numeric ($singular_id)) ? (int)$singular_id : false; // Force types.
65
  $uri = ($uri && is_string ($uri) && ($uri = c_ws_plugin__s2member_utils_urls::parse_uri ($uri))) ? $uri : false;
66
 
67
- if ($uri && preg_match ("/\/wp-admin(?:\/|\?|$)/", $uri)) // Inside a WordPress® administrative area?
68
  {
69
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_specific_page", true, get_defined_vars ()));
70
  }
@@ -72,7 +72,7 @@ if (!class_exists ("c_ws_plugin__s2member_systematics_sp"))
72
  {
73
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_specific_page", true, get_defined_vars ()));
74
  }
75
- else // Otherwise, we return false (i.e. it's NOT a WordPress® Systematic Use Page).
76
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_specific_page", false, get_defined_vars ()));
77
  }
78
  /**
@@ -81,7 +81,7 @@ if (!class_exists ("c_ws_plugin__s2member_systematics_sp"))
81
  * @package s2Member\Systematics
82
  * @since 3.5
83
  *
84
- * @param int|str $singular_id Optional. A numeric Post/Page ID in WordPress®.
85
  * @param str $uri Optional. A request URI to test against.
86
  * @return bool True if Systematic, else false.
87
  *
@@ -95,11 +95,11 @@ if (!class_exists ("c_ws_plugin__s2member_systematics_sp"))
95
  $singular_id = ($singular_id && is_numeric ($singular_id)) ? (int)$singular_id : false; // Force types.
96
  $uri = ($uri && is_string ($uri) && ($uri = c_ws_plugin__s2member_utils_urls::parse_uri ($uri))) ? $uri : false;
97
 
98
- if (c_ws_plugin__s2member_systematics_sp::is_s2_systematic_use_specific_page /* An s2Member® Systematic Use Page? */ ($singular_id, $uri))
99
  {
100
  return ($is_systematic = apply_filters ("ws_plugin__s2member_is_systematic_use_specific_page", true, get_defined_vars ()));
101
  }
102
- else if (c_ws_plugin__s2member_systematics_sp::is_wp_systematic_use_specific_page /* A WordPress® Systematic Use Page? */ ($singular_id, $uri))
103
  {
104
  return ($is_systematic = apply_filters ("ws_plugin__s2member_is_systematic_use_specific_page", true, get_defined_vars ()));
105
  }
28
  class c_ws_plugin__s2member_systematics_sp
29
  {
30
  /**
31
+ * Determines if a specific Post/Page ID, or URI, is s2Member Systematic.
32
  *
33
  * @package s2Member\Systematics
34
  * @since 111115
35
  *
36
+ * @param int|str $singular_id Optional. A numeric Post/Page ID in WordPress.
37
  * @param str $uri Optional. A request URI to test against.
38
+ * @return bool True if s2Member Systematic, else false.
39
  */
40
  public static function is_s2_systematic_use_specific_page ($singular_id = FALSE, $uri = FALSE)
41
  {
46
  {
47
  return ($is_s2_systematic = apply_filters ("ws_plugin__s2member_is_s2_systematic_use_specific_page", true, get_defined_vars ()));
48
  }
49
+ else // Otherwise, we return false (i.e. it's NOT an s2Member Systematic Use Page).
50
  return ($is_s2_systematic = apply_filters ("ws_plugin__s2member_is_s2_systematic_use_specific_page", false, get_defined_vars ()));
51
  }
52
  /**
53
+ * Determines if a specific Post/Page ID, or URI, is WordPress Systematic.
54
  *
55
  * @package s2Member\Systematics
56
  * @since 111002
57
  *
58
+ * @param int|str $singular_id Optional. A numeric Post/Page ID in WordPress.
59
  * @param str $uri Optional. A request URI to test against.
60
+ * @return bool True if WordPress Systematic, else false.
61
  */
62
  public static function is_wp_systematic_use_specific_page ($singular_id = FALSE, $uri = FALSE)
63
  {
64
  $singular_id = ($singular_id && is_numeric ($singular_id)) ? (int)$singular_id : false; // Force types.
65
  $uri = ($uri && is_string ($uri) && ($uri = c_ws_plugin__s2member_utils_urls::parse_uri ($uri))) ? $uri : false;
66
 
67
+ if ($uri && preg_match ("/\/wp-admin(?:\/|\?|$)/", $uri)) // Inside a WordPress administrative area?
68
  {
69
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_specific_page", true, get_defined_vars ()));
70
  }
72
  {
73
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_specific_page", true, get_defined_vars ()));
74
  }
75
+ else // Otherwise, we return false (i.e. it's NOT a WordPress Systematic Use Page).
76
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_specific_page", false, get_defined_vars ()));
77
  }
78
  /**
81
  * @package s2Member\Systematics
82
  * @since 3.5
83
  *
84
+ * @param int|str $singular_id Optional. A numeric Post/Page ID in WordPress.
85
  * @param str $uri Optional. A request URI to test against.
86
  * @return bool True if Systematic, else false.
87
  *
95
  $singular_id = ($singular_id && is_numeric ($singular_id)) ? (int)$singular_id : false; // Force types.
96
  $uri = ($uri && is_string ($uri) && ($uri = c_ws_plugin__s2member_utils_urls::parse_uri ($uri))) ? $uri : false;
97
 
98
+ if (c_ws_plugin__s2member_systematics_sp::is_s2_systematic_use_specific_page /* An s2Member Systematic Use Page? */ ($singular_id, $uri))
99
  {
100
  return ($is_systematic = apply_filters ("ws_plugin__s2member_is_systematic_use_specific_page", true, get_defined_vars ()));
101
  }
102
+ else if (c_ws_plugin__s2member_systematics_sp::is_wp_systematic_use_specific_page /* A WordPress Systematic Use Page? */ ($singular_id, $uri))
103
  {
104
  return ($is_systematic = apply_filters ("ws_plugin__s2member_is_systematic_use_specific_page", true, get_defined_vars ()));
105
  }
includes/classes/systematics.inc.php CHANGED
@@ -28,12 +28,12 @@ if (!class_exists ("c_ws_plugin__s2member_systematics"))
28
  class c_ws_plugin__s2member_systematics
29
  {
30
  /**
31
- * Determines if the current page is s2Member® Systematic.
32
  *
33
  * @package s2Member\Systematics
34
  * @since 111115
35
  *
36
- * @return bool True if s2Member® Systematic, else false.
37
  *
38
  * @note The results of this function are cached staticially.
39
  * Do NOT call upon this until the `init` Hook is fired.
@@ -50,16 +50,16 @@ if (!class_exists ("c_ws_plugin__s2member_systematics"))
50
  {
51
  return ($is_s2_systematic = apply_filters ("ws_plugin__s2member_is_s2_systematic_use_page", true, get_defined_vars ()));
52
  }
53
- else // Otherwise, we return false (it's NOT an s2Member® Systematic Use Page).
54
  return ($is_s2_systematic = apply_filters ("ws_plugin__s2member_is_s2_systematic_use_page", false, get_defined_vars ()));
55
  }
56
  /**
57
- * Determines if the current page is WordPress® Systematic.
58
  *
59
  * @package s2Member\Systematics
60
  * @since 111002
61
  *
62
- * @return bool True if WordPress® Systematic, else false.
63
  *
64
  * @note The results of this function are cached staticially.
65
  * Do NOT call upon this until the `init` Hook is fired.
@@ -76,11 +76,11 @@ if (!class_exists ("c_ws_plugin__s2member_systematics"))
76
  {
77
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_page", true, get_defined_vars ()));
78
  }
79
- else if (defined ("WP_INSTALLING") && WP_INSTALLING) // Installing? All WordPress® installs are considered Systematic.
80
  {
81
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_page", true, get_defined_vars ()));
82
  }
83
- else if (defined ("APP_REQUEST") && APP_REQUEST) // App request? All WordPress® app requests are considered Systematic.
84
  {
85
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_page", true, get_defined_vars ()));
86
  }
@@ -96,7 +96,7 @@ if (!class_exists ("c_ws_plugin__s2member_systematics"))
96
  {
97
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_page", true, get_defined_vars ()));
98
  }
99
- else // Otherwise, we return false (it's NOT a WordPress® Systematic Use Page).
100
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_page", false, get_defined_vars ()));
101
  }
102
  /**
@@ -118,11 +118,11 @@ if (!class_exists ("c_ws_plugin__s2member_systematics"))
118
  {
119
  return $is_systematic; // Filters will have already been applied here.
120
  }
121
- else if (c_ws_plugin__s2member_systematics::is_s2_systematic_use_page /* An s2Member® Systematic Use Page? */ ())
122
  {
123
  return ($is_systematic = apply_filters ("ws_plugin__s2member_is_systematic_use_page", true, get_defined_vars ()));
124
  }
125
- else if (c_ws_plugin__s2member_systematics::is_wp_systematic_use_page /* A WordPress® Systematic Use Page? */ ())
126
  {
127
  return ($is_systematic = apply_filters ("ws_plugin__s2member_is_systematic_use_page", true, get_defined_vars ()));
128
  }
28
  class c_ws_plugin__s2member_systematics
29
  {
30
  /**
31
+ * Determines if the current page is s2Member Systematic.
32
  *
33
  * @package s2Member\Systematics
34
  * @since 111115
35
  *
36
+ * @return bool True if s2Member Systematic, else false.
37
  *
38
  * @note The results of this function are cached staticially.
39
  * Do NOT call upon this until the `init` Hook is fired.
50
  {
51
  return ($is_s2_systematic = apply_filters ("ws_plugin__s2member_is_s2_systematic_use_page", true, get_defined_vars ()));
52
  }
53
+ else // Otherwise, we return false (it's NOT an s2Member Systematic Use Page).
54
  return ($is_s2_systematic = apply_filters ("ws_plugin__s2member_is_s2_systematic_use_page", false, get_defined_vars ()));
55
  }
56
  /**
57
+ * Determines if the current page is WordPress Systematic.
58
  *
59
  * @package s2Member\Systematics
60
  * @since 111002
61
  *
62
+ * @return bool True if WordPress Systematic, else false.
63
  *
64
  * @note The results of this function are cached staticially.
65
  * Do NOT call upon this until the `init` Hook is fired.
76
  {
77
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_page", true, get_defined_vars ()));
78
  }
79
+ else if (defined ("WP_INSTALLING") && WP_INSTALLING) // Installing? All WordPress installs are considered Systematic.
80
  {
81
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_page", true, get_defined_vars ()));
82
  }
83
+ else if (defined ("APP_REQUEST") && APP_REQUEST) // App request? All WordPress app requests are considered Systematic.
84
  {
85
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_page", true, get_defined_vars ()));
86
  }
96
  {
97
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_page", true, get_defined_vars ()));
98
  }
99
+ else // Otherwise, we return false (it's NOT a WordPress Systematic Use Page).
100
  return ($is_wp_systematic = apply_filters ("ws_plugin__s2member_is_wp_systematic_use_page", false, get_defined_vars ()));
101
  }
102
  /**
118
  {
119
  return $is_systematic; // Filters will have already been applied here.
120
  }
121
+ else if (c_ws_plugin__s2member_systematics::is_s2_systematic_use_page /* An s2Member Systematic Use Page? */ ())
122
  {
123
  return ($is_systematic = apply_filters ("ws_plugin__s2member_is_systematic_use_page", true, get_defined_vars ()));
124
  }
125
+ else if (c_ws_plugin__s2member_systematics::is_wp_systematic_use_page /* A WordPress Systematic Use Page? */ ())
126
  {
127
  return ($is_systematic = apply_filters ("ws_plugin__s2member_is_systematic_use_page", true, get_defined_vars ()));
128
  }
includes/classes/tracking-codes.inc.php CHANGED
@@ -38,7 +38,7 @@ if (!class_exists ("c_ws_plugin__s2member_tracking_codes"))
38
  * o On the Return URL / Thank-You Page, after returning from your Payment Gateway.
39
  * o Otherwise, on the Registration Form, after returning from your Payment Gateway.
40
  * o Otherwise, if possible, on the Login Form *(in the footer)* after Registration is completed.
41
- * o Otherwise, in the footer of your WordPress® theme, as soon as possible; or after the Customer's very first login.
42
  *
43
  * @package s2Member\Tracking
44
  * @since 3.5
@@ -90,7 +90,7 @@ if (!class_exists ("c_ws_plugin__s2member_tracking_codes"))
90
  *
91
  * o On the Return URL / Thank-You Page, after returning from your Payment Gateway.
92
  * o Otherwise, if possible, on the Login Form *(in the footer)* after returning from your Payment Gateway.
93
- * o Otherwise, in the footer of your WordPress® theme, as soon as possible; or after the Customer's next login.
94
  *
95
  * @package s2Member\Tracking
96
  * @since 110815
@@ -142,7 +142,7 @@ if (!class_exists ("c_ws_plugin__s2member_tracking_codes"))
142
  *
143
  * o On the Return URL / Thank-You Page, after returning from your Payment Gateway.
144
  * o Otherwise, if possible, on the Login Form *(in the footer)* after returning from your Payment Gateway.
145
- * o Otherwise, in the footer of your WordPress® theme, as soon as possible; or after the Customer's next login.
146
  *
147
  * @package s2Member\Tracking
148
  * @since 110815
38
  * o On the Return URL / Thank-You Page, after returning from your Payment Gateway.
39
  * o Otherwise, on the Registration Form, after returning from your Payment Gateway.
40
  * o Otherwise, if possible, on the Login Form *(in the footer)* after Registration is completed.
41
+ * o Otherwise, in the footer of your WordPress theme, as soon as possible; or after the Customer's very first login.
42
  *
43
  * @package s2Member\Tracking
44
  * @since 3.5
90
  *
91
  * o On the Return URL / Thank-You Page, after returning from your Payment Gateway.
92
  * o Otherwise, if possible, on the Login Form *(in the footer)* after returning from your Payment Gateway.
93
+ * o Otherwise, in the footer of your WordPress theme, as soon as possible; or after the Customer's next login.
94
  *
95
  * @package s2Member\Tracking
96
  * @since 110815
142
  *
143
  * o On the Return URL / Thank-You Page, after returning from your Payment Gateway.
144
  * o Otherwise, if possible, on the Login Form *(in the footer)* after returning from your Payment Gateway.
145
+ * o Otherwise, in the footer of your WordPress theme, as soon as possible; or after the Customer's next login.
146
  *
147
  * @package s2Member\Tracking
148
  * @since 110815
includes/classes/translations.inc.php CHANGED
@@ -50,7 +50,7 @@ if (!class_exists ("c_ws_plugin__s2member_translations"))
50
  /**
51
  * Handles internal translations via `gettext` Filter.
52
  *
53
- * Important note. Because this routine also uses translation functionality by WordPress®,
54
  * anything translated by this routine MUST be different, otherwise it will result in a recursive loop,
55
  * because the ``__()`` family of functions would be called upon recursively by this routine.
56
  *
50
  /**
51
  * Handles internal translations via `gettext` Filter.
52
  *
53
+ * Important note. Because this routine also uses translation functionality by WordPress,
54
  * anything translated by this routine MUST be different, otherwise it will result in a recursive loop,
55
  * because the ``__()`` family of functions would be called upon recursively by this routine.
56
  *
includes/classes/user-access.inc.php CHANGED
@@ -47,7 +47,7 @@ if (!class_exists ("c_ws_plugin__s2member_user_access"))
47
  {
48
  return apply_filters ("ws_plugin__s2member_user_access_role", "", get_defined_vars ());
49
  }
50
- else // Else we return the first Role in their array of assigned WordPress® Roles.
51
  return apply_filters ("ws_plugin__s2member_user_access_role", reset ($user->roles), get_defined_vars ());
52
  }
53
  /**
@@ -118,7 +118,7 @@ if (!class_exists ("c_ws_plugin__s2member_user_access"))
118
  * @package s2Member\User_Access
119
  * @since 3.5
120
  *
121
- * @param str $role A WordPress® Role ID/Name.
122
  * @return int Access Level#, `-1` if ``$role`` is empty.
123
  */
124
  public static function user_access_role_to_level ($role = FALSE)
47
  {
48
  return apply_filters ("ws_plugin__s2member_user_access_role", "", get_defined_vars ());
49
  }
50
+ else // Else we return the first Role in their array of assigned WordPress Roles.
51
  return apply_filters ("ws_plugin__s2member_user_access_role", reset ($user->roles), get_defined_vars ());
52
  }
53
  /**
118
  * @package s2Member\User_Access
119
  * @since 3.5
120
  *
121
+ * @param str $role A WordPress Role ID/Name.
122
  * @return int Access Level#, `-1` if ``$role`` is empty.
123
  */
124
  public static function user_access_role_to_level ($role = FALSE)
includes/classes/user-deletions.inc.php CHANGED
@@ -35,8 +35,8 @@ if (!class_exists ("c_ws_plugin__s2member_user_deletions"))
35
  *
36
  * @attaches-to ``add_action("remove_user_from_blog");``
37
  *
38
- * @param int|str $user_id Numeric WordPress® User ID.
39
- * @param int|str $blog_id Numeric WordPress® Blog ID.
40
  * @param bool $s2says Optional. Defaults to false. If true, it's definitely OK to process this deletion?
41
  * The ``$s2says`` flag can be used when/if the routine is called directly for whatever reason.
42
  * @return null
@@ -82,7 +82,7 @@ if (!class_exists ("c_ws_plugin__s2member_user_deletions"))
82
  * @attaches-to ``add_action("delete_user");``
83
  * @attaches-to ``add_action("wpmu_delete_user");``
84
  *
85
- * @param int|str $user_id Numeric WordPress® User ID.
86
  * @return null
87
  */
88
  public static function handle_user_deletions ($user_id = FALSE)
35
  *
36
  * @attaches-to ``add_action("remove_user_from_blog");``
37
  *
38
+ * @param int|str $user_id Numeric WordPress User ID.
39
+ * @param int|str $blog_id Numeric WordPress Blog ID.
40
  * @param bool $s2says Optional. Defaults to false. If true, it's definitely OK to process this deletion?
41
  * The ``$s2says`` flag can be used when/if the routine is called directly for whatever reason.
42
  * @return null
82
  * @attaches-to ``add_action("delete_user");``
83
  * @attaches-to ``add_action("wpmu_delete_user");``
84
  *
85
+ * @param int|str $user_id Numeric WordPress User ID.
86
  * @return null
87
  */
88
  public static function handle_user_deletions ($user_id = FALSE)
includes/classes/user-new-in.inc.php CHANGED
@@ -53,7 +53,7 @@ if (!class_exists ("c_ws_plugin__s2member_user_new_in"))
53
 
54
  $unfs = '<div style="margin:25px 0 25px 0; height:1px; line-height:1px; background:#CCCCCC;"></div>' . "\n";
55
 
56
- $unfs .= '<h3 style="position:relative;"><img src="' . esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]) . '/images/large-icon.png" title="s2Member (a Membership management system for WordPress®)" alt="" style="position:absolute; top:-15px; right:0; border:0;" />s2Member Configuration &amp; Profile Fields' . ((is_multisite ()) ? ' (for this Blog)' : '') . '</h3>' . "\n";
57
 
58
  $unfs .= '<table class="form-table">' . "\n";
59
 
@@ -95,9 +95,9 @@ if (!class_exists ("c_ws_plugin__s2member_user_new_in"))
95
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
96
 
97
  $unfs .= '<tr>' . "\n";
98
- $unfs .= '<th><label for="ws-plugin--s2member-user-new-s2member-subscr-gateway">Paid Subscr. Gateway:</label> <a href="#" onclick="alert(\'A Payment Gateway code is associated with the Paid Subscr. ID below. A Paid Subscription ID (or a Buy Now Transaction ID) is only valid for paid Members. Also known as ( a Recurring Profile ID, a ClickBank® Receipt #, a Google® TID/SID (with an s2 prefix), an AliPay® Trade No. ). Under normal circumstances, this is filled automatically by s2Member. This field is ONLY here for Customer Service purposes; just in case you ever need to enter a Paid Subscr. Gateway/ID manually. This field will be empty for Free Subscribers, and/or anyone who is NOT paying you.\\n\\nThe value of Paid® Subscr. ID, can be a PayPal® Standard `Subscription ID`, or a PayPal® Pro `Recurring Profile ID`, or a PayPal® `Transaction ID`; depending on the type of sale. Your PayPal® account will supply this information. If you\\\'re using Google® Checkout, use the TID/SID value in the sale Description; it always starts with `s2-`. ClickBank® provides a Receipt #, ccBill® provides a Subscription ID, Authorize.Net® provides a Subscription ID, and AliPay® provides a Transaction ID. The general rule is... IF there\\\'s a Subscription ID, use that! If there\\\'s NOT, use the Transaction ID.\'); return false;" tabindex="-1">[?]</a></th>' . "\n";
99
  $unfs .= '<td><select name="ws_plugin__s2member_user_new_s2member_subscr_gateway" id="ws-plugin--s2member-user-new-s2member-subscr-gateway" style="width:25em;"><option value=""></option>' . "\n";
100
- foreach (apply_filters ("ws_plugin__s2member_profile_s2member_subscr_gateways", array ("paypal" => "PayPal® (code: paypal)"), get_defined_vars ()) as $gateway => $gateway_name)
101
  $unfs .= '<option value="' . esc_attr ($gateway) . '"' . (($gateway === $_p["ws_plugin__s2member_user_new_s2member_subscr_gateway"]) ? ' selected="selected"' : '') . '>' . esc_html ($gateway_name) . '</option>' . "\n";
102
  $unfs .= '</select>' . "\n";
103
  $unfs .= '</td>' . "\n";
@@ -112,7 +112,7 @@ if (!class_exists ("c_ws_plugin__s2member_user_new_in"))
112
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
113
 
114
  $unfs .= '<tr>' . "\n";
115
- $unfs .= '<th><label for="ws-plugin--s2member-user-new-s2member-subscr-id">Paid Subscr. ID:</label> <a href="#" onclick="alert(\'A Paid Subscription ID (or a Buy Now Transaction ID) is only valid for paid Members. Also known as ( a Recurring Profile ID, a ClickBank® Receipt #, a Google® TID/SID (with an s2 prefix), an AliPay® Trade No. ). Under normal circumstances, this is filled automatically by s2Member. This field is ONLY here for Customer Service purposes; just in case you ever need to enter a Paid Subscr. Gateway/ID manually. This field will be empty for Free Subscribers, and/or anyone who is NOT paying you.\\n\\nThe value of Paid® Subscr. ID, can be a PayPal® Standard `Subscription ID`, or a PayPal® Pro `Recurring Profile ID`, or a PayPal® `Transaction ID`; depending on the type of sale. Your PayPal® account will supply this information. If you\\\'re using Google® Checkout, use the TID/SID value in the sale Description; it always starts with `s2-`. ClickBank® provides a Receipt #, ccBill® provides a Subscription ID, Authorize.Net® provides a Subscription ID, and AliPay® provides a Transaction ID. The general rule is... if there\\\'s a Subscription ID, use that! If there\\\'s NOT, use the Transaction ID.\'); return false;" tabindex="-1">[?]</a></th>' . "\n";
116
  $unfs .= '<td><input type="text" autocomplete="off" name="ws_plugin__s2member_user_new_s2member_subscr_id" id="ws-plugin--s2member-user-new-s2member-subscr-id" value="' . format_to_edit ($_p["ws_plugin__s2member_user_new_s2member_subscr_id"]) . '" class="regular-text" /></td>' . "\n";
117
  $unfs .= '</tr>' . "\n";
118
 
53
 
54
  $unfs = '<div style="margin:25px 0 25px 0; height:1px; line-height:1px; background:#CCCCCC;"></div>' . "\n";
55
 
56
+ $unfs .= '<h3 style="position:relative;"><img src="' . esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]) . '/images/large-icon.png" title="s2Member (a Membership management system for WordPress)" alt="" style="position:absolute; top:-15px; right:0; border:0;" />s2Member Configuration &amp; Profile Fields' . ((is_multisite ()) ? ' (for this Blog)' : '') . '</h3>' . "\n";
57
 
58
  $unfs .= '<table class="form-table">' . "\n";
59
 
95
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
96
 
97
  $unfs .= '<tr>' . "\n";
98
+ $unfs .= '<th><label for="ws-plugin--s2member-user-new-s2member-subscr-gateway">Paid Subscr. Gateway:</label> <a href="#" onclick="alert(\'A Payment Gateway code is associated with the Paid Subscr. ID below. A Paid Subscription ID (or a Buy Now Transaction ID) is only valid for paid Members. Also known as ( a Recurring Profile ID, a ClickBank Receipt #, a Google TID/SID (with an s2 prefix), an AliPay Trade No. ). Under normal circumstances, this is filled automatically by s2Member. This field is ONLY here for Customer Service purposes; just in case you ever need to enter a Paid Subscr. Gateway/ID manually. This field will be empty for Free Subscribers, and/or anyone who is NOT paying you.\\n\\nThe value of Paid Subscr. ID, can be a PayPal Standard `Subscription ID`, or a PayPal Pro `Recurring Profile ID`, or a PayPal `Transaction ID`; depending on the type of sale. Your PayPal account will supply this information. If you\\\'re using Google Checkout, use the TID/SID value in the sale Description; it always starts with `s2-`. ClickBank provides a Receipt #, ccBill provides a Subscription ID, Authorize.Net provides a Subscription ID, and AliPay provides a Transaction ID. The general rule is... IF there\\\'s a Subscription ID, use that! If there\\\'s NOT, use the Transaction ID.\'); return false;" tabindex="-1">[?]</a></th>' . "\n";
99
  $unfs .= '<td><select name="ws_plugin__s2member_user_new_s2member_subscr_gateway" id="ws-plugin--s2member-user-new-s2member-subscr-gateway" style="width:25em;"><option value=""></option>' . "\n";
100
+ foreach (apply_filters ("ws_plugin__s2member_profile_s2member_subscr_gateways", array ("paypal" => "PayPal (code: paypal)"), get_defined_vars ()) as $gateway => $gateway_name)
101
  $unfs .= '<option value="' . esc_attr ($gateway) . '"' . (($gateway === $_p["ws_plugin__s2member_user_new_s2member_subscr_gateway"]) ? ' selected="selected"' : '') . '>' . esc_html ($gateway_name) . '</option>' . "\n";
102
  $unfs .= '</select>' . "\n";
103
  $unfs .= '</td>' . "\n";
112
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
113
 
114
  $unfs .= '<tr>' . "\n";
115
+ $unfs .= '<th><label for="ws-plugin--s2member-user-new-s2member-subscr-id">Paid Subscr. ID:</label> <a href="#" onclick="alert(\'A Paid Subscription ID (or a Buy Now Transaction ID) is only valid for paid Members. Also known as ( a Recurring Profile ID, a ClickBank Receipt #, a Google TID/SID (with an s2 prefix), an AliPay Trade No. ). Under normal circumstances, this is filled automatically by s2Member. This field is ONLY here for Customer Service purposes; just in case you ever need to enter a Paid Subscr. Gateway/ID manually. This field will be empty for Free Subscribers, and/or anyone who is NOT paying you.\\n\\nThe value of Paid Subscr. ID, can be a PayPal Standard `Subscription ID`, or a PayPal Pro `Recurring Profile ID`, or a PayPal `Transaction ID`; depending on the type of sale. Your PayPal account will supply this information. If you\\\'re using Google Checkout, use the TID/SID value in the sale Description; it always starts with `s2-`. ClickBank provides a Receipt #, ccBill provides a Subscription ID, Authorize.Net provides a Subscription ID, and AliPay provides a Transaction ID. The general rule is... if there\\\'s a Subscription ID, use that! If there\\\'s NOT, use the Transaction ID.\'); return false;" tabindex="-1">[?]</a></th>' . "\n";
116
  $unfs .= '<td><input type="text" autocomplete="off" name="ws_plugin__s2member_user_new_s2member_subscr_id" id="ws-plugin--s2member-user-new-s2member-subscr-id" value="' . format_to_edit ($_p["ws_plugin__s2member_user_new_s2member_subscr_id"]) . '" class="regular-text" /></td>' . "\n";
117
  $unfs .= '</tr>' . "\n";
118
 
includes/classes/user-notes.inc.php CHANGED
@@ -33,7 +33,7 @@ if (!class_exists ("c_ws_plugin__s2member_user_notes"))
33
  * @package s2Member\Admin_Notes
34
  * @since 3.5
35
  *
36
- * @param int|str $user_id A numeric WordPress® User ID.
37
  * @param str $notes The string of notes to append. One note, or many.
38
  * @return str The full set of notes, including appendage.
39
  */
@@ -62,7 +62,7 @@ if (!class_exists ("c_ws_plugin__s2member_user_notes"))
62
  * @package s2Member\Admin_Notes
63
  * @since 3.5
64
  *
65
- * @param int|str $user_id A numeric WordPress® User ID.
66
  * @param str $regex A regular expression to match against each line.
67
  * @return str The full set of notes, after clearing.
68
  */
33
  * @package s2Member\Admin_Notes
34
  * @since 3.5
35
  *
36
+ * @param int|str $user_id A numeric WordPress User ID.
37
  * @param str $notes The string of notes to append. One note, or many.
38
  * @return str The full set of notes, including appendage.
39
  */
62
  * @package s2Member\Admin_Notes
63
  * @since 3.5
64
  *
65
+ * @param int|str $user_id A numeric WordPress User ID.
66
  * @param str $regex A regular expression to match against each line.
67
  * @return str The full set of notes, after clearing.
68
  */
includes/classes/user-securities.inc.php CHANGED
@@ -30,7 +30,7 @@ if (!class_exists ("c_ws_plugin__s2member_user_securities"))
30
  /**
31
  * Initializes Filter for `user_has_cap`.
32
  *
33
- * It's very important that this is NOT attached before WordPress® creates `$current_user` via `$wp->init()`.
34
  * This prevents crashes when other plugins attempt to call upon `current_user_can()` before WordPress is initialized.
35
  * For instance, some plugins attempt to use `current_user_can()` on the `plugins_loaded` Hook, which they should not do.
36
  *
@@ -57,9 +57,9 @@ if (!class_exists ("c_ws_plugin__s2member_user_securities"))
57
  * This array contains all of the Capabilities that the User has *( i.e. ``$user->allcaps`` )*.
58
  * @param array $caps_map An array of Capabilities mapped out by the ``map_meta_cap`` function.
59
  * @param array $args Array of arguments originally passed through the ``has_cap()`` function.
60
- * However, WordPress® modifies this array of arguments in the following way.
61
  * Argument `[0]` is the Capability test string itself *(this is normal)*.
62
- * Argument `[1]` is added by WordPress®; it's the ID of the User.
63
  * Other arguments starting from array index `[2]` are normal.
64
  * @return array An array of Capabilities.
65
  */
30
  /**
31
  * Initializes Filter for `user_has_cap`.
32
  *
33
+ * It's very important that this is NOT attached before WordPress creates `$current_user` via `$wp->init()`.
34
  * This prevents crashes when other plugins attempt to call upon `current_user_can()` before WordPress is initialized.
35
  * For instance, some plugins attempt to use `current_user_can()` on the `plugins_loaded` Hook, which they should not do.
36
  *
57
  * This array contains all of the Capabilities that the User has *( i.e. ``$user->allcaps`` )*.
58
  * @param array $caps_map An array of Capabilities mapped out by the ``map_meta_cap`` function.
59
  * @param array $args Array of arguments originally passed through the ``has_cap()`` function.
60
+ * However, WordPress modifies this array of arguments in the following way.
61
  * Argument `[0]` is the Capability test string itself *(this is normal)*.
62
+ * Argument `[1]` is added by WordPress; it's the ID of the User.
63
  * Other arguments starting from array index `[2]` are normal.
64
  * @return array An array of Capabilities.
65
  */
includes/classes/users-list-in.inc.php CHANGED
@@ -51,14 +51,14 @@ if(!class_exists("c_ws_plugin__s2member_users_list_in"))
51
 
52
  if(is_object($user) && !empty($user->ID) && ($user_id = $user->ID) && is_object($current_user) && !empty($current_user->ID))
53
  {
54
- $role = c_ws_plugin__s2member_user_access::user_access_role($user); // This User's current WordPress® Role.
55
  $level = c_ws_plugin__s2member_user_access::user_access_level($user); // User's Access Level for s2Member.
56
 
57
  if(current_user_can("edit_users") && (!is_multisite() || is_super_admin() || is_user_member_of_blog($user_id)))
58
  {
59
  echo '<div style="margin:25px 0 25px 0; height:1px; line-height:1px; background:#CCCCCC;"></div>'."\n";
60
 
61
- echo '<h3 style="position:relative;"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/large-icon.png" title="s2Member (a Membership management system for WordPress®)" alt="" style="position:absolute; top:-15px; right:0; border:0;" />s2Member Configuration &amp; Profile Fields'.((is_multisite()) ? ' (for this Blog)' : '').'</h3>'."\n";
62
 
63
  echo '<table class="form-table">'."\n";
64
 
@@ -74,7 +74,7 @@ if(!class_exists("c_ws_plugin__s2member_users_list_in"))
74
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
75
 
76
  echo '<tr>'."\n";
77
- echo '<th><label for="ws-plugin--s2member-profile-s2member-originating-blog">Originating Blog ID#:</label> <a href="#" onclick="alert(\'On a Multisite Network, this is how s2Member keeps track of which Blog each User/Member originated from. So this ID#, is automatically associated with a Blog in your Network, matching the User\\\'s point of origin. ~ ONLY a Super Admin can modify this.\\n\\nOn a Multisite Blog Farm, the Originating Blog ID# for your own Customers, will ALWAYS be associated with your (Main Site). It is NOT likely that you\\\'ll need to modify this manually, but s2Member makes it available; just in case.\\n\\n*Tip* - If you add Users (and/or Blogs) with the `Super Admin` Network Administration panel inside WordPress®, then you WILL need to set everything manually. s2Member does NOT tamper with automation routines whenever YOU (as a Super Administrator) are working in that area.\'); return false;" tabindex="-1">[?]</a></th>'."\n";
78
  echo '<td><input type="text" autocomplete="off" name="ws_plugin__s2member_profile_s2member_originating_blog" id="ws-plugin--s2member-profile-s2member-originating-blog" value="'.format_to_edit(get_user_meta($user_id, "s2member_originating_blog", true)).'" class="regular-text" /></td>'."\n";
79
  echo '</tr>'."\n";
80
 
@@ -88,9 +88,9 @@ if(!class_exists("c_ws_plugin__s2member_users_list_in"))
88
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
89
 
90
  echo '<tr>'."\n";
91
- echo '<th><label for="ws-plugin--s2member-profile-s2member-subscr-gateway">Paid Subscr. Gateway:</label> <a href="#" onclick="alert(\'A Payment Gateway code is associated with the Paid Subscr. ID below. A Paid Subscription ID (or a Buy Now Transaction ID) is only valid for paid Members. Also known as ( a Recurring Profile ID, a ClickBank® Receipt #, a Google® TID/SID (with an s2 prefix), an AliPay® Trade No. ). This will be filled automatically by s2Member.\\n\\nThis field will be empty for Free Subscribers, and/or anyone who is NOT paying you. This field is only editable for Customer Service purposes; just in case you ever need to update the Paid Subscr. Gateway/ID manually.\\n\\nThe value of Paid® Subscr. ID, can be a PayPal® Standard `Subscription ID`, or a PayPal® Pro `Recurring Profile ID`, or a PayPal® `Transaction ID`; depending on the type of sale. Your PayPal® account will supply this information. If you\\\'re using Google® Checkout, use the TID/SID value in the sale Description; it always starts with `s2-`. ClickBank® provides a Receipt #, ccBill® provides a Subscription ID, Authorize.Net® provides a Subscription ID, and AliPay® provides a Transaction ID. The general rule is... IF there\\\'s a Subscription ID, use that! If there\\\'s NOT, use the Transaction ID.\'); return false;" tabindex="-1">[?]</a></th>'."\n";
92
  echo '<td><select name="ws_plugin__s2member_profile_s2member_subscr_gateway" id="ws-plugin--s2member-profile-s2member-subscr-gateway" style="width:25em;"><option value=""></option>'."\n";
93
- foreach(apply_filters("ws_plugin__s2member_profile_s2member_subscr_gateways", array("paypal" => "PayPal® (code: paypal)"), get_defined_vars()) as $gateway => $gateway_name)
94
  echo '<option value="'.esc_attr($gateway).'"'.(($gateway === get_user_option("s2member_subscr_gateway", $user_id)) ? ' selected="selected"' : '').'>'.esc_html($gateway_name).'</option>'."\n";
95
  echo '</select>'."\n";
96
  echo '</td>'."\n";
@@ -105,7 +105,7 @@ if(!class_exists("c_ws_plugin__s2member_users_list_in"))
105
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
106
 
107
  echo '<tr>'."\n";
108
- echo '<th><label for="ws-plugin--s2member-profile-s2member-subscr-id">Paid Subscr. ID:</label> <a href="#" onclick="alert(\'A Paid Subscription ID (or a Buy Now Transaction ID) is only valid for paid Members. Also known as ( a Recurring Profile ID, a ClickBank® Receipt #, a Google® TID/SID (with an s2 prefix), an AliPay® Trade No. ). This will be filled automatically by s2Member.\\n\\nThis field will be empty for Free Subscribers, and/or anyone who is NOT paying you. This field is only editable for Customer Service purposes; just in case you ever need to update the Paid Subscr. Gateway/ID manually.\\n\\nThe value of Paid® Subscr. ID, can be a PayPal® Standard `Subscription ID`, or a PayPal® Pro `Recurring Profile ID`, or a PayPal® `Transaction ID`; depending on the type of sale. Your PayPal® account will supply this information. If you\\\'re using Google® Checkout, use the TID/SID value in the sale Description; it always starts with `s2-`. ClickBank® provides a Receipt #, ccBill® provides a Subscription ID, Authorize.Net® provides a Subscription ID, and AliPay® provides a Transaction ID. The general rule is... IF there\\\'s a Subscription ID, use that! If there\\\'s NOT, use the Transaction ID.\'); return false;" tabindex="-1">[?]</a></th>'."\n";
109
  echo '<td><input type="text" autocomplete="off" name="ws_plugin__s2member_profile_s2member_subscr_id" id="ws-plugin--s2member-profile-s2member-subscr-id" value="'.format_to_edit(get_user_option("s2member_subscr_id", $user_id)).'" class="regular-text" /></td>'."\n";
110
  echo '</tr>'."\n";
111
 
@@ -184,7 +184,7 @@ if(!class_exists("c_ws_plugin__s2member_users_list_in"))
184
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
185
 
186
  echo '<tr>'."\n";
187
- echo '<th><label for="ws-plugin--s2member-profile-reset-pass-resend">Reset Password &amp; Resend Welcome Email Message:</label> <a href="#" onclick="alert(\'Checking this box will tell s2Member® to reset this User\\\'s password and then reprocess the New User Email Notification message against this User\\\'s account. This way they\\\'ll get an email message with their Username/Password.\\n\\nThis can be helpful in cases where a User/Member missed the original email message for some reason.\\n\\nThe User\\\'s password is reset to a new auto-generated password by default. However, you can provide a custom password by entering a new password of your choosing in the field above — provided by WordPress® itself.\\n\\nIt is also possible to customize the New User Email Notification message with s2Member®. Please see: `Dashboard -› s2Member® -› General Options -› Email Configuration -› New User Notifications`.\'); return false;" tabindex="-1">[?]</a></th>'."\n";
188
  echo '<td><label><input type="checkbox" name="ws_plugin__s2member_profile_reset_pass_resend" id="ws-plugin--s2member-profile-reset-pass-resend" value="1" /> Yes, reset password &amp; resend welcome email message to this User.</label></td>'."\n";
189
  echo '</tr>'."\n";
190
 
@@ -218,7 +218,7 @@ if(!class_exists("c_ws_plugin__s2member_users_list_in"))
218
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
219
 
220
  echo '<tr>'."\n";
221
- echo '<th><label for="ws-plugin--s2member-custom-reg-auto-opt-out-transitions">Allow List Transitioning:</label> <a href="#" onclick="alert(\'You\\\'ve configured s2Member with List Transitions enabled. By leaving this box checked, s2Member will Transition the User\\\'s mailing list subscription(s) automatically. For example, if a Member is demoted from Level #2, down to Level #1; s2Member will add them to the Level #1 List(s) after it removes them from the Level #2 List(s).\\n\\nDepending on your configuration of s2Member®, a transition may ONLY occur if s2Member IS able to successfully remove them from an existing List. In other words, if they are currently NOT subscribed to any List(s), s2Member may NOT transition them to any new Lists (depending on your configuration).\'); return false;" tabindex="-1">[?]</a></th>'."\n";
222
  echo '<td><label><input type="checkbox" name="ws_plugin__s2member_custom_reg_auto_opt_out_transitions" id="ws-plugin--s2member-custom-reg-auto-opt-out-transitions" value="1" checked="checked" /> Yes, automatically transition this User\'s mailing list subscription(s) when/if I change their Role.</label></td>'."\n";
223
  echo '</tr>'."\n";
224
 
@@ -400,7 +400,7 @@ if(!class_exists("c_ws_plugin__s2member_users_list_in"))
400
  * @attaches-to ``add_action("edit_user_profile_update");``
401
  * @attaches-to ``add_action("personal_options_update");``
402
  *
403
- * @param int|str $user_id Expects a numeric WordPress® User ID passed in by the Action Hook.
404
  * @return null
405
  */
406
  public static function users_list_update_cols($user_id = FALSE)
51
 
52
  if(is_object($user) && !empty($user->ID) && ($user_id = $user->ID) && is_object($current_user) && !empty($current_user->ID))
53
  {
54
+ $role = c_ws_plugin__s2member_user_access::user_access_role($user); // This User's current WordPress Role.
55
  $level = c_ws_plugin__s2member_user_access::user_access_level($user); // User's Access Level for s2Member.
56
 
57
  if(current_user_can("edit_users") && (!is_multisite() || is_super_admin() || is_user_member_of_blog($user_id)))
58
  {
59
  echo '<div style="margin:25px 0 25px 0; height:1px; line-height:1px; background:#CCCCCC;"></div>'."\n";
60
 
61
+ echo '<h3 style="position:relative;"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/large-icon.png" title="s2Member (a Membership management system for WordPress)" alt="" style="position:absolute; top:-15px; right:0; border:0;" />s2Member Configuration &amp; Profile Fields'.((is_multisite()) ? ' (for this Blog)' : '').'</h3>'."\n";
62
 
63
  echo '<table class="form-table">'."\n";
64
 
74
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
75
 
76
  echo '<tr>'."\n";
77
+ echo '<th><label for="ws-plugin--s2member-profile-s2member-originating-blog">Originating Blog ID#:</label> <a href="#" onclick="alert(\'On a Multisite Network, this is how s2Member keeps track of which Blog each User/Member originated from. So this ID#, is automatically associated with a Blog in your Network, matching the User\\\'s point of origin. ~ ONLY a Super Admin can modify this.\\n\\nOn a Multisite Blog Farm, the Originating Blog ID# for your own Customers, will ALWAYS be associated with your (Main Site). It is NOT likely that you\\\'ll need to modify this manually, but s2Member makes it available; just in case.\\n\\n*Tip* - If you add Users (and/or Blogs) with the `Super Admin` Network Administration panel inside WordPress, then you WILL need to set everything manually. s2Member does NOT tamper with automation routines whenever YOU (as a Super Administrator) are working in that area.\'); return false;" tabindex="-1">[?]</a></th>'."\n";
78
  echo '<td><input type="text" autocomplete="off" name="ws_plugin__s2member_profile_s2member_originating_blog" id="ws-plugin--s2member-profile-s2member-originating-blog" value="'.format_to_edit(get_user_meta($user_id, "s2member_originating_blog", true)).'" class="regular-text" /></td>'."\n";
79
  echo '</tr>'."\n";
80
 
88
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
89
 
90
  echo '<tr>'."\n";
91
+ echo '<th><label for="ws-plugin--s2member-profile-s2member-subscr-gateway">Paid Subscr. Gateway:</label> <a href="#" onclick="alert(\'A Payment Gateway code is associated with the Paid Subscr. ID below. A Paid Subscription ID (or a Buy Now Transaction ID) is only valid for paid Members. Also known as ( a Recurring Profile ID, a ClickBank Receipt #, a Google TID/SID (with an s2 prefix), an AliPay Trade No. ). This will be filled automatically by s2Member.\\n\\nThis field will be empty for Free Subscribers, and/or anyone who is NOT paying you. This field is only editable for Customer Service purposes; just in case you ever need to update the Paid Subscr. Gateway/ID manually.\\n\\nThe value of Paid Subscr. ID, can be a PayPal Standard `Subscription ID`, or a PayPal Pro `Recurring Profile ID`, or a PayPal `Transaction ID`; depending on the type of sale. Your PayPal account will supply this information. If you\\\'re using Google Checkout, use the TID/SID value in the sale Description; it always starts with `s2-`. ClickBank provides a Receipt #, ccBill provides a Subscription ID, Authorize.Net provides a Subscription ID, and AliPay provides a Transaction ID. The general rule is... IF there\\\'s a Subscription ID, use that! If there\\\'s NOT, use the Transaction ID.\'); return false;" tabindex="-1">[?]</a></th>'."\n";
92
  echo '<td><select name="ws_plugin__s2member_profile_s2member_subscr_gateway" id="ws-plugin--s2member-profile-s2member-subscr-gateway" style="width:25em;"><option value=""></option>'."\n";
93
+ foreach(apply_filters("ws_plugin__s2member_profile_s2member_subscr_gateways", array("paypal" => "PayPal (code: paypal)"), get_defined_vars()) as $gateway => $gateway_name)
94
  echo '<option value="'.esc_attr($gateway).'"'.(($gateway === get_user_option("s2member_subscr_gateway", $user_id)) ? ' selected="selected"' : '').'>'.esc_html($gateway_name).'</option>'."\n";
95
  echo '</select>'."\n";
96
  echo '</td>'."\n";
105
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
106
 
107
  echo '<tr>'."\n";
108
+ echo '<th><label for="ws-plugin--s2member-profile-s2member-subscr-id">Paid Subscr. ID:</label> <a href="#" onclick="alert(\'A Paid Subscription ID (or a Buy Now Transaction ID) is only valid for paid Members. Also known as ( a Recurring Profile ID, a ClickBank Receipt #, a Google TID/SID (with an s2 prefix), an AliPay Trade No. ). This will be filled automatically by s2Member.\\n\\nThis field will be empty for Free Subscribers, and/or anyone who is NOT paying you. This field is only editable for Customer Service purposes; just in case you ever need to update the Paid Subscr. Gateway/ID manually.\\n\\nThe value of Paid Subscr. ID, can be a PayPal Standard `Subscription ID`, or a PayPal Pro `Recurring Profile ID`, or a PayPal `Transaction ID`; depending on the type of sale. Your PayPal account will supply this information. If you\\\'re using Google Checkout, use the TID/SID value in the sale Description; it always starts with `s2-`. ClickBank provides a Receipt #, ccBill provides a Subscription ID, Authorize.Net provides a Subscription ID, and AliPay provides a Transaction ID. The general rule is... IF there\\\'s a Subscription ID, use that! If there\\\'s NOT, use the Transaction ID.\'); return false;" tabindex="-1">[?]</a></th>'."\n";
109
  echo '<td><input type="text" autocomplete="off" name="ws_plugin__s2member_profile_s2member_subscr_id" id="ws-plugin--s2member-profile-s2member-subscr-id" value="'.format_to_edit(get_user_option("s2member_subscr_id", $user_id)).'" class="regular-text" /></td>'."\n";
110
  echo '</tr>'."\n";
111
 
184
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
185
 
186
  echo '<tr>'."\n";
187
+ echo '<th><label for="ws-plugin--s2member-profile-reset-pass-resend">Reset Password &amp; Resend Welcome Email Message:</label> <a href="#" onclick="alert(\'Checking this box will tell s2Member to reset this User\\\'s password and then reprocess the New User Email Notification message against this User\\\'s account. This way they\\\'ll get an email message with their Username/Password.\\n\\nThis can be helpful in cases where a User/Member missed the original email message for some reason.\\n\\nThe User\\\'s password is reset to a new auto-generated password by default. However, you can provide a custom password by entering a new password of your choosing in the field above — provided by WordPress itself.\\n\\nIt is also possible to customize the New User Email Notification message with s2Member. Please see: `Dashboard -› s2Member -› General Options -› Email Configuration -› New User Notifications`.\'); return false;" tabindex="-1">[?]</a></th>'."\n";
188
  echo '<td><label><input type="checkbox" name="ws_plugin__s2member_profile_reset_pass_resend" id="ws-plugin--s2member-profile-reset-pass-resend" value="1" /> Yes, reset password &amp; resend welcome email message to this User.</label></td>'."\n";
189
  echo '</tr>'."\n";
190
 
218
  unset /* Unset defined __refs, __v. */ ($__refs, $__v);
219
 
220
  echo '<tr>'."\n";
221
+ echo '<th><label for="ws-plugin--s2member-custom-reg-auto-opt-out-transitions">Allow List Transitioning:</label> <a href="#" onclick="alert(\'You\\\'ve configured s2Member with List Transitions enabled. By leaving this box checked, s2Member will Transition the User\\\'s mailing list subscription(s) automatically. For example, if a Member is demoted from Level #2, down to Level #1; s2Member will add them to the Level #1 List(s) after it removes them from the Level #2 List(s).\\n\\nDepending on your configuration of s2Member, a transition may ONLY occur if s2Member IS able to successfully remove them from an existing List. In other words, if they are currently NOT subscribed to any List(s), s2Member may NOT transition them to any new Lists (depending on your configuration).\'); return false;" tabindex="-1">[?]</a></th>'."\n";
222
  echo '<td><label><input type="checkbox" name="ws_plugin__s2member_custom_reg_auto_opt_out_transitions" id="ws-plugin--s2member-custom-reg-auto-opt-out-transitions" value="1" checked="checked" /> Yes, automatically transition this User\'s mailing list subscription(s) when/if I change their Role.</label></td>'."\n";
223
  echo '</tr>'."\n";
224
 
400
  * @attaches-to ``add_action("edit_user_profile_update");``
401
  * @attaches-to ``add_action("personal_options_update");``
402
  *
403
+ * @param int|str $user_id Expects a numeric WordPress User ID passed in by the Action Hook.
404
  * @return null
405
  */
406
  public static function users_list_update_cols($user_id = FALSE)
includes/classes/users-list.inc.php CHANGED
@@ -52,7 +52,7 @@ if (!class_exists ("c_ws_plugin__s2member_users_list"))
52
  * @attaches-to ``add_action("edit_user_profile_update");``
53
  * @attaches-to ``add_action("personal_options_update");``
54
  *
55
- * @param int|str $user_id Expects a numeric WordPress® User ID passed in by the Action Hook.
56
  * @return inner Return-value of inner routine.
57
  */
58
  public static function users_list_update_cols ($user_id = FALSE)
@@ -164,7 +164,7 @@ if (!class_exists ("c_ws_plugin__s2member_users_list"))
164
  *
165
  * @param str $val A value for this column, passed through by the Filter.
166
  * @param str $col The name of the column for which we might need to supply data for.
167
- * @param int|str $user_id Expects a WordPress® User ID, passed through by the Filter.
168
  * @return str A column value introduced by this routine, or existing value, or, if empty, a dash.
169
  */
170
  public static function users_list_display_cols ($val = FALSE, $col = FALSE, $user_id = FALSE)
52
  * @attaches-to ``add_action("edit_user_profile_update");``
53
  * @attaches-to ``add_action("personal_options_update");``
54
  *
55
+ * @param int|str $user_id Expects a numeric WordPress User ID passed in by the Action Hook.
56
  * @return inner Return-value of inner routine.
57
  */
58
  public static function users_list_update_cols ($user_id = FALSE)
164
  *
165
  * @param str $val A value for this column, passed through by the Filter.
166
  * @param str $col The name of the column for which we might need to supply data for.
167
+ * @param int|str $user_id Expects a WordPress User ID, passed through by the Filter.
168
  * @return str A column value introduced by this routine, or existing value, or, if empty, a dash.
169
  */
170
  public static function users_list_display_cols ($val = FALSE, $col = FALSE, $user_id = FALSE)
includes/classes/utilities.inc.php CHANGED
@@ -117,17 +117,17 @@ if (!class_exists ("c_ws_plugin__s2member_utilities"))
117
  return $details; // Return all details.
118
  }
119
  /**
120
- * String with all version details *(for PHP, WordPress®, s2Member, and Pro)*.
121
  *
122
  * @package s2Member\Utilities
123
  * @since 3.5
124
  *
125
- * @return str String with `PHP vX.XX :: WordPress® vX.XX :: s2Member® vX.XX :: s2Member® Pro vX.XX`.
126
  */
127
  public static function ver_details ()
128
  {
129
- $details = "PHP v" . PHP_VERSION . " :: WordPress® v" . get_bloginfo ("version") . " :: s2Member® v" . WS_PLUGIN__S2MEMBER_VERSION;
130
- $details .= (c_ws_plugin__s2member_utils_conds::pro_is_installed ()) ? " :: s2Member® Pro v" . WS_PLUGIN__S2MEMBER_PRO_VERSION : "";
131
 
132
  return $details; // Return all details.
133
  }
117
  return $details; // Return all details.
118
  }
119
  /**
120
+ * String with all version details *(for PHP, WordPress, s2Member, and Pro)*.
121
  *
122
  * @package s2Member\Utilities
123
  * @since 3.5
124
  *
125
+ * @return str String with `PHP vX.XX :: WordPress vX.XX :: s2Member vX.XX :: s2Member Pro vX.XX`.
126
  */
127
  public static function ver_details ()
128
  {
129
+ $details = "PHP v" . PHP_VERSION . " :: WordPress v" . get_bloginfo ("version") . " :: s2Member v" . WS_PLUGIN__S2MEMBER_VERSION;
130
+ $details .= (c_ws_plugin__s2member_utils_conds::pro_is_installed ()) ? " :: s2Member Pro v" . WS_PLUGIN__S2MEMBER_PRO_VERSION : "";
131
 
132
  return $details; // Return all details.
133
  }
includes/classes/utils-captchas.inc.php CHANGED
@@ -43,7 +43,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_captchas"))
43
  return apply_filters ("ws_plugin__s2member_recaptcha_keys", array ("public" => $public, "private" => $private), get_defined_vars ());
44
  }
45
  /**
46
- * Verifies a reCAPTCHA™ code via Google®.
47
  *
48
  * @package s2Member\Utilities
49
  * @since 3.5
43
  return apply_filters ("ws_plugin__s2member_recaptcha_keys", array ("public" => $public, "private" => $private), get_defined_vars ());
44
  }
45
  /**
46
+ * Verifies a reCAPTCHA™ code via Google.
47
  *
48
  * @package s2Member\Utilities
49
  * @since 3.5
includes/classes/utils-conds.inc.php CHANGED
@@ -91,7 +91,7 @@ if(!class_exists("c_ws_plugin__s2member_utils_conds"))
91
  * @since 3.5
92
  *
93
  * @param array $cats An array of Category IDs.
94
- * @param int|str $post_id A numeric WordPress® Post ID.
95
  * @return bool True if the Post is inside a desendant of at least one of the specified Categories; else false.
96
  */
97
  public static function in_descendant_category($cats = FALSE, $post_id = FALSE)
@@ -142,12 +142,12 @@ if(!class_exists("c_ws_plugin__s2member_utils_conds"))
142
  return /* Default return false. */ false;
143
  }
144
  /**
145
- * Checks to see if we're using Amazon® S3.
146
  *
147
  * @package s2Member\Utilities
148
  * @since 110926
149
  *
150
- * @return bool True if using Amazon® S3, else false.
151
  */
152
  public static function using_amazon_s3_storage()
153
  {
@@ -161,12 +161,12 @@ if(!class_exists("c_ws_plugin__s2member_utils_conds"))
161
  return /* Default return false. */ false;
162
  }
163
  /**
164
- * Checks to see if we're using Amazon® CloudFront.
165
  *
166
  * @package s2Member\Utilities
167
  * @since 110926
168
  *
169
- * @return bool True if using Amazon® CloudFront, else false.
170
  */
171
  public static function using_amazon_cf_storage()
172
  {
91
  * @since 3.5
92
  *
93
  * @param array $cats An array of Category IDs.
94
+ * @param int|str $post_id A numeric WordPress Post ID.
95
  * @return bool True if the Post is inside a desendant of at least one of the specified Categories; else false.
96
  */
97
  public static function in_descendant_category($cats = FALSE, $post_id = FALSE)
142
  return /* Default return false. */ false;
143
  }
144
  /**
145
+ * Checks to see if we're using Amazon S3.
146
  *
147
  * @package s2Member\Utilities
148
  * @since 110926
149
  *
150
+ * @return bool True if using Amazon S3, else false.
151
  */
152
  public static function using_amazon_s3_storage()
153
  {
161
  return /* Default return false. */ false;
162
  }
163
  /**
164
+ * Checks to see if we're using Amazon CloudFront.
165
  *
166
  * @package s2Member\Utilities
167
  * @since 110926
168
  *
169
+ * @return bool True if using Amazon CloudFront, else false.
170
  */
171
  public static function using_amazon_cf_storage()
172
  {
includes/classes/utils-cur.inc.php CHANGED
@@ -30,7 +30,7 @@ if(!class_exists("c_ws_plugin__s2member_utils_cur"))
30
  /**
31
  * Currency converter.
32
  *
33
- * Uses the Google® currency conversion API.
34
  *
35
  * @package s2Member\Utilities
36
  * @since 3.5
30
  /**
31
  * Currency converter.
32
  *
33
+ * Uses the Google currency conversion API.
34
  *
35
  * @package s2Member\Utilities
36
  * @since 3.5
includes/classes/utils-dirs.inc.php CHANGED
@@ -92,7 +92,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_dirs"))
92
  * @param str $from The full directory path to calculate a relative path `from`.
93
  * @param str $to The full directory or file path, which this routine will build a relative path `to`.
94
  * @param bool $try_realpaths Defaults to true. When true, try to acquire ``realpath()``, thereby resolving all relative paths and/or symlinks in ``$from`` and ``$to`` args.
95
- * @param bool $use_win_diff_drive_jctn Defaults to true. When true, we'll work around issues with different drives on Windows® by trying to create a directory junction.
96
  * @return str String with the relative path to: ``$to``.
97
  */
98
  public static function rel_path ($from = FALSE, $to = FALSE, $try_realpaths = TRUE, $use_win_diff_drive_jctn = TRUE)
@@ -110,7 +110,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_dirs"))
110
  $from = preg_split ("/\//", $from); // Convert ``$from``, to an array. Split on each directory separator.
111
  $to = preg_split ("/\//", $to); // Also convert ``$to``, to an array. Split this on each directory separator.
112
 
113
- if ($use_win_diff_drive_jctn && stripos (PHP_OS, "win") === 0 /* Test for different drives on Windows® servers? */)
114
 
115
  if (/*Drive? */preg_match ("/^([A-Z])\:$/i", $from[0], $_m) && ($_from_drive = $_m[1]) && preg_match ("/^([A-Z])\:$/i", $to[0], $_m) && ($_to_drive = $_m[1]))
116
  if ( /* Are these locations on completely different drives? */$_from_drive !== $_to_drive)
@@ -128,7 +128,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_dirs"))
128
  }
129
  else // Else, we should trigger an error in this case. It's NOT possible to generate this.
130
  {
131
- trigger_error ("Unable to generate a relative path across different Windows® drives." .
132
  " Please create a Directory Junction here: " . $_from_drive_jctn . ", pointing to: " . $_to_drive . ":/", E_USER_ERROR);
133
  }
134
  }
@@ -159,7 +159,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_dirs"))
159
  return implode ("/", $rel_path);
160
  }
161
  /**
162
- * Creates a directory Junction in Windows®.
163
  *
164
  * @package s2Member\Utilities
165
  * @since 111013
@@ -192,7 +192,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_dirs"))
192
  * @package s2Member\Utilities
193
  * @since 111017
194
  *
195
- * @param str $fallback Defaults to true. If true, fallback on WordPress® routine if not available, or if not writable.
196
  * @return str|bool Full string path to a writable temp directory, else false on failure.
197
  */
198
  public static function get_temp_dir ($fallback = TRUE)
92
  * @param str $from The full directory path to calculate a relative path `from`.
93
  * @param str $to The full directory or file path, which this routine will build a relative path `to`.
94
  * @param bool $try_realpaths Defaults to true. When true, try to acquire ``realpath()``, thereby resolving all relative paths and/or symlinks in ``$from`` and ``$to`` args.
95
+ * @param bool $use_win_diff_drive_jctn Defaults to true. When true, we'll work around issues with different drives on Windows by trying to create a directory junction.
96
  * @return str String with the relative path to: ``$to``.
97
  */
98
  public static function rel_path ($from = FALSE, $to = FALSE, $try_realpaths = TRUE, $use_win_diff_drive_jctn = TRUE)
110
  $from = preg_split ("/\//", $from); // Convert ``$from``, to an array. Split on each directory separator.
111
  $to = preg_split ("/\//", $to); // Also convert ``$to``, to an array. Split this on each directory separator.
112
 
113
+ if ($use_win_diff_drive_jctn && stripos (PHP_OS, "win") === 0 /* Test for different drives on Windows servers? */)
114
 
115
  if (/*Drive? */preg_match ("/^([A-Z])\:$/i", $from[0], $_m) && ($_from_drive = $_m[1]) && preg_match ("/^([A-Z])\:$/i", $to[0], $_m) && ($_to_drive = $_m[1]))
116
  if ( /* Are these locations on completely different drives? */$_from_drive !== $_to_drive)
128
  }
129
  else // Else, we should trigger an error in this case. It's NOT possible to generate this.
130
  {
131
+ trigger_error ("Unable to generate a relative path across different Windows drives." .
132
  " Please create a Directory Junction here: " . $_from_drive_jctn . ", pointing to: " . $_to_drive . ":/", E_USER_ERROR);
133
  }
134
  }
159
  return implode ("/", $rel_path);
160
  }
161
  /**
162
+ * Creates a directory Junction in Windows.
163
  *
164
  * @package s2Member\Utilities
165
  * @since 111013
192
  * @package s2Member\Utilities
193
  * @since 111017
194
  *
195
+ * @param str $fallback Defaults to true. If true, fallback on WordPress routine if not available, or if not writable.
196
  * @return str|bool Full string path to a writable temp directory, else false on failure.
197
  */
198
  public static function get_temp_dir ($fallback = TRUE)
includes/classes/utils-encryption.inc.php CHANGED
@@ -39,7 +39,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_encryption"))
39
  public static function key ($key = FALSE)
40
  {
41
  $key = (!is_string ($key) || !strlen ($key)) ? $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key"] : $key;
42
- $key = (!is_string ($key) || !strlen ($key)) ? /* Use the installed WordPress® salt. */ wp_salt () : $key;
43
  $key = (!is_string ($key) || !strlen ($key)) ? /* Default/backup. */ md5 ($_SERVER["HTTP_HOST"]) : $key;
44
  return /* Proper encryption/decryption key. */ $key;
45
  }
39
  public static function key ($key = FALSE)
40
  {
41
  $key = (!is_string ($key) || !strlen ($key)) ? $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key"] : $key;
42
+ $key = (!is_string ($key) || !strlen ($key)) ? /* Use the installed WordPress salt. */ wp_salt () : $key;
43
  $key = (!is_string ($key) || !strlen ($key)) ? /* Default/backup. */ md5 ($_SERVER["HTTP_HOST"]) : $key;
44
  return /* Proper encryption/decryption key. */ $key;
45
  }
includes/classes/utils-gets.inc.php CHANGED
@@ -39,7 +39,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_gets"))
39
  */
40
  public static function get_all_category_ids ()
41
  {
42
- if (is_array ($category_ids = /* Uses the WordPress® function for this. */ get_all_category_ids ()))
43
  $category_ids = c_ws_plugin__s2member_utils_arrays::force_integers ($category_ids);
44
 
45
  return (!empty ($category_ids) && is_array ($category_ids)) ? array_unique ($category_ids) : array ();
@@ -253,8 +253,9 @@ if (!class_exists ("c_ws_plugin__s2member_utils_gets"))
253
 
254
  foreach (($posts = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"])) as $p)
255
  if (strpos ($p, "all-") === 0 && preg_match ("/^all-(.+)$/", $p, $m) /* Protecting `all-` of a specific Post Type? */)
256
- if (is_array ($p_of_type = c_ws_plugin__s2member_utils_gets::get_all_post_ids ($m[1])) && !empty ($p_of_type))
257
- $x_ids = array_merge /* Merge all Posts of this Post Type. */ ($x_ids, $p_of_type);
 
258
 
259
  $x_ids = /* Exclude the full list too. */ array_merge ($x_ids, $posts);
260
  unset /* Just a little housekeeping here. */ ($posts, $p, $m, $p_of_type);
39
  */
40
  public static function get_all_category_ids ()
41
  {
42
+ if (is_array ($category_ids = /* Uses the WordPress function for this. */ get_all_category_ids ()))
43
  $category_ids = c_ws_plugin__s2member_utils_arrays::force_integers ($category_ids);
44
 
45
  return (!empty ($category_ids) && is_array ($category_ids)) ? array_unique ($category_ids) : array ();
253
 
254
  foreach (($posts = preg_split ("/[\r\n\t\s;,]+/", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_posts"])) as $p)
255
  if (strpos ($p, "all-") === 0 && preg_match ("/^all-(.+)$/", $p, $m) /* Protecting `all-` of a specific Post Type? */)
256
+ if ((is_array ($p_of_type = c_ws_plugin__s2member_utils_gets::get_all_post_ids ($m[1])) || (substr($m[1], -1) === "s"
257
+ && is_array($_p_of_type = c_ws_plugin__s2member_utils_gets::get_all_post_ids(substr($m[1], 0, -1)))))
258
+ && !empty ($p_of_type)) $x_ids = array_merge /* Merge all Posts of this Post Type. */ ($x_ids, $p_of_type);
259
 
260
  $x_ids = /* Exclude the full list too. */ array_merge ($x_ids, $posts);
261
  unset /* Just a little housekeeping here. */ ($posts, $p, $m, $p_of_type);
includes/classes/utils-logs.inc.php CHANGED
@@ -37,35 +37,35 @@ if (!class_exists ("c_ws_plugin__s2member_utils_logs"))
37
  */
38
  public static $log_file_descriptions = array // Array keys are regex patterns matching their associated log file names.
39
  (
40
- '/paypal-api/' => array('short' => 'PayPal® API communication.', 'long' => 'This log file records all communication between s2Member® and PayPal® APIs. Such as PayPal® Button Encryption and PayPal® Pro API calls that process transactions. See also: paypal-ipn.log (s2Member\'s core processor).'),
41
- '/paypal-payflow-api/' => array('short' => 'PayPal® (PayFlow Edition) API communication.', 'long' => 'This log file records all communication between s2Member® and the PayPal® (PayFlow Edition) APIs. Only applicable if you operate a PayPal® Payments Pro (PayFlow Edition) account. See also: paypal-ipn.log (s2Member\'s core processor).'),
42
- '/paypal-ipn/' => array('short' => 'Core PayPal® IPN and post-processing handler.', 'long' => 'This log file records all communication between s2Member® and the PayPal® IPN service. Also logs all post-processing routines from other Payment Gateway integrations, where s2Member® translates its communication with other Payment Gateways into a format it\'s core PayPal® processing routines can understand. All transactions pass through s2Member\'s core PayPal® processor and they will be logged in this file. Including transactions processed via s2Member® Pro Forms; for all Payment Gateway integrations.'),
43
- '/paypal-rtn/' => array('short' => 'Core PayPal® PDT/Auto-Return communication.', 'long' => 'This log file records all communication between s2Member® and the PayPal® PDT Auto-Return system (i.e. routines that help s2Member® process Thank-You pages). Also logs all Auto-Return routines from other Payment Gateway integrations (those implemented via Payment Buttons), where s2Member® translates its communication with other Payment Gateways into a format it\'s core PayPal® processing routines can understand. Not used in s2Member® Pro Form integrations however.'),
44
 
45
- '/authnet-api/' => array('short' => 'Authorize.Net API communication.', 'long' => 'This log file records all communication between s2Member® and Authorize.Net APIs (for both AIM and ARB integrations).'),
46
- '/authnet-arb/' => array('short' => 'Authorize.Net ARB Subscription status checks.', 'long' => 'This log file records s2Member\'s Authorize.Net ARB Subscription status checks. s2Member® polls the ARB service periodically to check the status of existing Members (e.g. to see if billing is still active or not).'),
47
- '/authnet-ipn/' => array('short' => 'Authorize.Net Silent Post/IPN communication.', 'long' => 'This log file records the Silent Post/IPN data Authorize.Net sends to s2Member® with details regarding new transactions.'),
48
 
49
- '/alipay-ipn/' => array('short' => 'AliPay® IPN communication.', 'long' => 'This log file records the IPN data AliPay® sends to s2Member® with details regarding new transactions. See also: paypal-ipn.log (s2Member\'s core processor).'),
50
- '/alipay-rtn/' => array('short' => 'AliPay® Auto-Return communication.', 'long' => 'This log file records the Auto-Return data AliPay® sends to s2Member® with details regarding new transactions (i.e. logs routines that help s2Member® process Thank-You pages). See also: paypal-rtn.log (s2Member\'s core processor).'),
51
 
52
- '/clickbank-ipn/' => array('short' => 'ClickBank® IPN communication.', 'long' => 'This log file records the IPN data ClickBank® sends to s2Member® with details regarding new transactions, cancellations, expirations, etc. See also: paypal-ipn.log (s2Member\'s core processor).'),
53
- '/clickbank-rtn/' => array('short' => 'ClickBank® Auto-Return communication.', 'long' => 'This log file records the Auto-Return data ClickBank® sends to s2Member® with details regarding new transactions (i.e. logs routines that help s2Member® process Thank-You pages). See also: paypal-rtn.log (s2Member\'s core processor).'),
54
 
55
- '/google-ipn/' => array('short' => 'Google® Callback/IPN communication.', 'long' => 'This log file records the Callback/IPN data Google® sends to s2Member® with details regarding new transactions, cancellations, expirations, etc. See also: paypal-ipn.log (s2Member\'s core processor).'),
56
 
57
- '/ccbill-ipn/' => array('short' => 'ccBill® Bg Post/IPN communication.', 'long' => 'This log file records the Bg Post/IPN data ccBill® sends to s2Member® with details regarding new transactions. See also: paypal-ipn.log (s2Member\'s core processor).'),
58
- '/ccbill-rtn/' => array('short' => 'ccBill® Auto-Return communication.', 'long' => 'This log file records the Auto-Return data ccBill® sends to s2Member® with details regarding new transactions (i.e. logs routines that help s2Member® process Thank-You pages). See also: paypal-rtn.log (s2Member\'s core processor).'),
59
- '/ccbill-dl-ipn/' => array('short' => 'ccBill® Datalink Subscription status checks.', 'long' => 'This log file records s2Member\'s ccBill® Datalink Subscription status checks that may result in actions taken by s2Member®. s2Member® polls the ccBill® Datalink service periodically to check the status of existing Members (e.g. to see if billing is still active or not).'),
60
- '/ccbill-dl/' => array('short' => 'ccBill® Datalink collections.', 'long' => 'This log file records s2Member\'s ccBill® Datalink connections. s2Member® polls the ccBill® Datalink service periodically to obtain information about existing Users/Members.'),
61
 
62
- '/mailchimp-api/' => array('short' => 'MailChimp® API communication.', 'long' => 'This log file records all of s2Member\'s communication with MailChimp® APIs.'),
63
- '/aweber-api/' => array('short' => 'AWeber® API communication.', 'long' => 'This log file records all of s2Member\'s communication with AWeber® APIs.'),
64
 
65
- '/reg-handler/' => array('short' => 'User registrations processed by s2Member®.', 'long' => 'This log file records all User/Member registrations processed by s2Member® (either directly or indirectly). This includes both free and paid registrations. It also logs registrations that occur as a result of new Users/Members being created from the Dashboard by a site owner. It also includes registrations that occur through the s2Member® Pro Remote Operations API.'),
66
 
67
- '/s2-http-api-debug/' => array('short' => 'All outgoing HTTP connections related to s2Member®.', 'long' => 'This log file records all outgoing WP_Http connections that are specifically related to s2Member®. This log file can be extremely helpful. It includes technical details about remote HTTP connections that are not available in other log files.'),
68
- '/wp-http-api-debug/' => array('short' => 'All outgoing WordPress® HTTP connections.', 'long' => 'This log file records all outgoing HTTP connections processed by the WP_Http class. This includes everything processed by WordPress®; even things unrelated to s2Member®. This log file can be extremely helpful. It includes technical details about remote HTTP connections that are not available in other log files.'),
69
  );
70
 
71
  /**
@@ -115,7 +115,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_logs"))
115
  $http_api_debug_conceal_private_info . "\n\n",
116
  FILE_APPEND);
117
 
118
- if($is_s2member) // Log s2Member® HTTP connections separately.
119
  file_put_contents ($logs_dir . "/s2-" . $log2,
120
  "LOG ENTRY: ".$logt . "\n" . $logv . "\n" . $logm . "\n" . $log4 . "\n" .
121
  $http_api_debug_conceal_private_info . "\n\n",
37
  */
38
  public static $log_file_descriptions = array // Array keys are regex patterns matching their associated log file names.
39
  (
40
+ '/paypal-api/' => array('short' => 'PayPal API communication.', 'long' => 'This log file records all communication between s2Member and PayPal APIs. Such as PayPal Button Encryption and PayPal Pro API calls that process transactions. See also: paypal-ipn.log (s2Member\'s core processor).'),
41
+ '/paypal-payflow-api/' => array('short' => 'PayPal (PayFlow Edition) API communication.', 'long' => 'This log file records all communication between s2Member and the PayPal (PayFlow Edition) APIs. Only applicable if you operate a PayPal Payments Pro (PayFlow Edition) account. See also: paypal-ipn.log (s2Member\'s core processor).'),
42
+ '/paypal-ipn/' => array('short' => 'Core PayPal IPN and post-processing handler.', 'long' => 'This log file records all communication between s2Member and the PayPal IPN service. Also logs all post-processing routines from other Payment Gateway integrations, where s2Member translates its communication with other Payment Gateways into a format it\'s core PayPal processing routines can understand. All transactions pass through s2Member\'s core PayPal processor and they will be logged in this file. Including transactions processed via s2Member Pro Forms; for all Payment Gateway integrations.'),
43
+ '/paypal-rtn/' => array('short' => 'Core PayPal PDT/Auto-Return communication.', 'long' => 'This log file records all communication between s2Member and the PayPal PDT Auto-Return system (i.e. routines that help s2Member process Thank-You pages). Also logs all Auto-Return routines from other Payment Gateway integrations (those implemented via Payment Buttons), where s2Member translates its communication with other Payment Gateways into a format it\'s core PayPal processing routines can understand. Not used in s2Member Pro Form integrations however.'),
44
 
45
+ '/authnet-api/' => array('short' => 'Authorize.Net API communication.', 'long' => 'This log file records all communication between s2Member and Authorize.Net APIs (for both AIM and ARB integrations).'),
46
+ '/authnet-arb/' => array('short' => 'Authorize.Net ARB Subscription status checks.', 'long' => 'This log file records s2Member\'s Authorize.Net ARB Subscription status checks. s2Member polls the ARB service periodically to check the status of existing Members (e.g. to see if billing is still active or not).'),
47
+ '/authnet-ipn/' => array('short' => 'Authorize.Net Silent Post/IPN communication.', 'long' => 'This log file records the Silent Post/IPN data Authorize.Net sends to s2Member with details regarding new transactions.'),
48
 
49
+ '/alipay-ipn/' => array('short' => 'AliPay IPN communication.', 'long' => 'This log file records the IPN data AliPay sends to s2Member with details regarding new transactions. See also: paypal-ipn.log (s2Member\'s core processor).'),
50
+ '/alipay-rtn/' => array('short' => 'AliPay Auto-Return communication.', 'long' => 'This log file records the Auto-Return data AliPay sends to s2Member with details regarding new transactions (i.e. logs routines that help s2Member process Thank-You pages). See also: paypal-rtn.log (s2Member\'s core processor).'),
51
 
52
+ '/clickbank-ipn/' => array('short' => 'ClickBank IPN communication.', 'long' => 'This log file records the IPN data ClickBank sends to s2Member with details regarding new transactions, cancellations, expirations, etc. See also: paypal-ipn.log (s2Member\'s core processor).'),
53
+ '/clickbank-rtn/' => array('short' => 'ClickBank Auto-Return communication.', 'long' => 'This log file records the Auto-Return data ClickBank sends to s2Member with details regarding new transactions (i.e. logs routines that help s2Member process Thank-You pages). See also: paypal-rtn.log (s2Member\'s core processor).'),
54
 
55
+ '/google-ipn/' => array('short' => 'Google Callback/IPN communication.', 'long' => 'This log file records the Callback/IPN data Google sends to s2Member with details regarding new transactions, cancellations, expirations, etc. See also: paypal-ipn.log (s2Member\'s core processor).'),
56
 
57
+ '/ccbill-ipn/' => array('short' => 'ccBill Bg Post/IPN communication.', 'long' => 'This log file records the Bg Post/IPN data ccBill sends to s2Member with details regarding new transactions. See also: paypal-ipn.log (s2Member\'s core processor).'),
58
+ '/ccbill-rtn/' => array('short' => 'ccBill Auto-Return communication.', 'long' => 'This log file records the Auto-Return data ccBill sends to s2Member with details regarding new transactions (i.e. logs routines that help s2Member process Thank-You pages). See also: paypal-rtn.log (s2Member\'s core processor).'),
59
+ '/ccbill-dl-ipn/' => array('short' => 'ccBill Datalink Subscription status checks.', 'long' => 'This log file records s2Member\'s ccBill Datalink Subscription status checks that may result in actions taken by s2Member. s2Member polls the ccBill Datalink service periodically to check the status of existing Members (e.g. to see if billing is still active or not).'),
60
+ '/ccbill-dl/' => array('short' => 'ccBill Datalink collections.', 'long' => 'This log file records s2Member\'s ccBill Datalink connections. s2Member polls the ccBill Datalink service periodically to obtain information about existing Users/Members.'),
61
 
62
+ '/mailchimp-api/' => array('short' => 'MailChimp API communication.', 'long' => 'This log file records all of s2Member\'s communication with MailChimp APIs.'),
63
+ '/aweber-api/' => array('short' => 'AWeber API communication.', 'long' => 'This log file records all of s2Member\'s communication with AWeber APIs.'),
64
 
65
+ '/reg-handler/' => array('short' => 'User registrations processed by s2Member.', 'long' => 'This log file records all User/Member registrations processed by s2Member (either directly or indirectly). This includes both free and paid registrations. It also logs registrations that occur as a result of new Users/Members being created from the Dashboard by a site owner. It also includes registrations that occur through the s2Member Pro Remote Operations API.'),
66
 
67
+ '/s2-http-api-debug/' => array('short' => 'All outgoing HTTP connections related to s2Member.', 'long' => 'This log file records all outgoing WP_Http connections that are specifically related to s2Member. This log file can be extremely helpful. It includes technical details about remote HTTP connections that are not available in other log files.'),
68
+ '/wp-http-api-debug/' => array('short' => 'All outgoing WordPress HTTP connections.', 'long' => 'This log file records all outgoing HTTP connections processed by the WP_Http class. This includes everything processed by WordPress; even things unrelated to s2Member. This log file can be extremely helpful. It includes technical details about remote HTTP connections that are not available in other log files.'),
69
  );
70
 
71
  /**
115
  $http_api_debug_conceal_private_info . "\n\n",
116
  FILE_APPEND);
117
 
118
+ if($is_s2member) // Log s2Member HTTP connections separately.
119
  file_put_contents ($logs_dir . "/s2-" . $log2,
120
  "LOG ENTRY: ".$logt . "\n" . $logv . "\n" . $logm . "\n" . $log4 . "\n" .
121
  $http_api_debug_conceal_private_info . "\n\n",
includes/classes/utils-s2o.inc.php CHANGED
@@ -25,14 +25,14 @@ if (!class_exists ("c_ws_plugin__s2member_utils_s2o"))
25
  class c_ws_plugin__s2member_utils_s2o
26
  {
27
  /*
28
- * WordPress® directory.
29
  *
30
  * @package s2Member\Utilities
31
  * @since 110912
32
  *
33
  * @param str $starting_dir A directory to start searching from.
34
  * @param str $alt_starting_dir An alternate directory to search from.
35
- * @return str|null WordPress® directory, else exits script execution on failure.
36
  */
37
  public static function wp_dir ($starting_dir = FALSE, $alt_starting_dir = FALSE)
38
  {
@@ -45,17 +45,17 @@ if (!class_exists ("c_ws_plugin__s2member_utils_s2o"))
45
  header ("HTTP/1.0 500 Error");
46
  header ("Content-Type: text/plain; charset=UTF-8");
47
  while (@ob_end_clean ()); // Clean any existing output buffers.
48
- exit ("ERROR: s2Member® unable to locate WordPress® directory.");
49
  }
50
  /*
51
- * WordPress® settings, after ``SHORTINIT`` section.
52
  *
53
  * @package s2Member\Utilities
54
  * @since 110912
55
  *
56
- * @param str $wp_dir WordPress® directory path.
57
  * @param str $o_file Location of calling `*-o.php` file.
58
- * @return str|bool WordPress® settings, else false on failure.
59
  */
60
  public static function wp_settings_as ($wp_dir = FALSE, $o_file = FALSE)
61
  {
@@ -84,7 +84,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_s2o"))
84
  {
85
  if (($_wp_settings = str_replace ("__FILE__", '"' . str_replace ('"', '\"', $o_file) . '"', $_wp_settings))) // Eval compatible.
86
  {
87
- if (($_wp_settings = trim ($_wp_settings))) // WordPress®, with s2Member only.
88
  return ($wp_settings_as = $_wp_settings); // After ``SHORTINIT``.
89
  }
90
  }
25
  class c_ws_plugin__s2member_utils_s2o
26
  {
27
  /*
28
+ * WordPress directory.
29
  *
30
  * @package s2Member\Utilities
31
  * @since 110912
32
  *
33
  * @param str $starting_dir A directory to start searching from.
34
  * @param str $alt_starting_dir An alternate directory to search from.
35
+ * @return str|null WordPress directory, else exits script execution on failure.
36
  */
37
  public static function wp_dir ($starting_dir = FALSE, $alt_starting_dir = FALSE)
38
  {
45
  header ("HTTP/1.0 500 Error");
46
  header ("Content-Type: text/plain; charset=UTF-8");
47
  while (@ob_end_clean ()); // Clean any existing output buffers.
48
+ exit ("ERROR: s2Member unable to locate WordPress directory.");
49
  }
50
  /*
51
+ * WordPress settings, after ``SHORTINIT`` section.
52
  *
53
  * @package s2Member\Utilities
54
  * @since 110912
55
  *
56
+ * @param str $wp_dir WordPress directory path.
57
  * @param str $o_file Location of calling `*-o.php` file.
58
+ * @return str|bool WordPress settings, else false on failure.
59
  */
60
  public static function wp_settings_as ($wp_dir = FALSE, $o_file = FALSE)
61
  {
84
  {
85
  if (($_wp_settings = str_replace ("__FILE__", '"' . str_replace ('"', '\"', $o_file) . '"', $_wp_settings))) // Eval compatible.
86
  {
87
+ if (($_wp_settings = trim ($_wp_settings))) // WordPress, with s2Member only.
88
  return ($wp_settings_as = $_wp_settings); // After ``SHORTINIT``.
89
  }
90
  }
includes/classes/utils-time.inc.php CHANGED
@@ -31,7 +31,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_time"))
31
  * Determines the difference between two timestamps.
32
  *
33
  * Returns the difference in a human readable format.
34
- * Supports: minutes, hours, days, weeks, months, and years. This is an improvement on WordPress® ``human_time_diff()``.
35
  * This returns an "approximate" time difference. Rounded to the nearest minute, hour, day, week, month, year.
36
  *
37
  * @package s2Member\Utilities
@@ -106,7 +106,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_time"))
106
  * @package s2Member\Utilities
107
  * @since 3.5
108
  *
109
- * @param int|str $user_id Optional. A WordPress® User ID.
110
  * @param str $period1 Optional. First Intial "Period Term" *( i.e. `0 D` )*.
111
  * Only used when ``$user_id`` is passed in.
112
  * @param str $period3 Optional. Regular "Period Term" *( i.e. `1 M` )*.
31
  * Determines the difference between two timestamps.
32
  *
33
  * Returns the difference in a human readable format.
34
+ * Supports: minutes, hours, days, weeks, months, and years. This is an improvement on WordPress ``human_time_diff()``.
35
  * This returns an "approximate" time difference. Rounded to the nearest minute, hour, day, week, month, year.
36
  *
37
  * @package s2Member\Utilities
106
  * @package s2Member\Utilities
107
  * @since 3.5
108
  *
109
+ * @param int|str $user_id Optional. A WordPress User ID.
110
  * @param str $period1 Optional. First Intial "Period Term" *( i.e. `0 D` )*.
111
  * Only used when ``$user_id`` is passed in.
112
  * @param str $period3 Optional. Regular "Period Term" *( i.e. `1 M` )*.
includes/classes/utils-urls.inc.php CHANGED
@@ -28,7 +28,7 @@ if(!class_exists("c_ws_plugin__s2member_utils_urls"))
28
  class c_ws_plugin__s2member_utils_urls
29
  {
30
  /**
31
- * Builds a WordPress® signup URL to `/wp-signup.php`.
32
  *
33
  * @package s2Member\Utilities
34
  * @since 3.5
@@ -40,7 +40,7 @@ if(!class_exists("c_ws_plugin__s2member_utils_urls"))
40
  return apply_filters("wp_signup_location", site_url("/wp-signup.php"));
41
  }
42
  /**
43
- * Builds a WordPress® registration URL to `/wp-login.php?action=register`.
44
  *
45
  * @package s2Member\Utilities
46
  * @since 3.5
@@ -92,7 +92,7 @@ if(!class_exists("c_ws_plugin__s2member_utils_urls"))
92
  /**
93
  * Encodes all types of amperands to `amp;`, for use in XHTML code.
94
  *
95
- * Note however, this is usually NOT necessary. Just use WordPress® ``esc_html()`` or ``esc_attr()``.
96
  *
97
  * @package s2Member\Utilities
98
  * @since 111106
@@ -194,7 +194,7 @@ if(!class_exists("c_ws_plugin__s2member_utils_urls"))
194
  {
195
  $args = /* Force array, and disable SSL verification. */ (!is_array($args)) ? array(): $args;
196
 
197
- $args["s2member"] = WS_PLUGIN__S2MEMBER_VERSION; // Indicates this is an s2Member® connection.
198
 
199
  $args["sslverify"] = (!isset($args["sslverify"])) ? /* Off. */ false : $args["sslverify"];
200
 
@@ -266,7 +266,7 @@ if(!class_exists("c_ws_plugin__s2member_utils_urls"))
266
  return /* The default tinyURL API: <http://tinyurl.com/api-create.php?url=http://www.example.com/>. */ ($shorter_url = $tiny_url);
267
 
268
  else if($api === "goo_gl" && ($goo_gl = json_decode(trim(c_ws_plugin__s2member_utils_urls::remote("https://www.googleapis.com/urlshortener/v1/url".((($goo_gl_key = apply_filters("ws_plugin__s2member_url_shorten_api_goo_gl_key", false))) ? "?key=".urlencode($goo_gl_key) : ""), json_encode(array("longUrl" => $url)), array("headers" => array("Content-Type" => "application/json")))), true)) && !empty($goo_gl["id"]) && is_string($goo_gl_url = $goo_gl["id"]) && stripos($goo_gl_url, "http") === 0)
269
- return /* Google® API: <http://code.google.com/apis/urlshortener/v1/getting_started.html>. */ ($shorter_url = $goo_gl_url);
270
 
271
  else if /* Try backups? This way we can still shorten the URL with a backup. */($try_backups && count($apis) > 1)
272
 
28
  class c_ws_plugin__s2member_utils_urls
29
  {
30
  /**
31
+ * Builds a WordPress signup URL to `/wp-signup.php`.
32
  *
33
  * @package s2Member\Utilities
34
  * @since 3.5
40
  return apply_filters("wp_signup_location", site_url("/wp-signup.php"));
41
  }
42
  /**
43
+ * Builds a WordPress registration URL to `/wp-login.php?action=register`.
44
  *
45
  * @package s2Member\Utilities
46
  * @since 3.5
92
  /**
93
  * Encodes all types of amperands to `amp;`, for use in XHTML code.
94
  *
95
+ * Note however, this is usually NOT necessary. Just use WordPress ``esc_html()`` or ``esc_attr()``.
96
  *
97
  * @package s2Member\Utilities
98
  * @since 111106
194
  {
195
  $args = /* Force array, and disable SSL verification. */ (!is_array($args)) ? array(): $args;
196
 
197
+ $args["s2member"] = WS_PLUGIN__S2MEMBER_VERSION; // Indicates this is an s2Member connection.
198
 
199
  $args["sslverify"] = (!isset($args["sslverify"])) ? /* Off. */ false : $args["sslverify"];
200
 
266
  return /* The default tinyURL API: <http://tinyurl.com/api-create.php?url=http://www.example.com/>. */ ($shorter_url = $tiny_url);
267
 
268
  else if($api === "goo_gl" && ($goo_gl = json_decode(trim(c_ws_plugin__s2member_utils_urls::remote("https://www.googleapis.com/urlshortener/v1/url".((($goo_gl_key = apply_filters("ws_plugin__s2member_url_shorten_api_goo_gl_key", false))) ? "?key=".urlencode($goo_gl_key) : ""), json_encode(array("longUrl" => $url)), array("headers" => array("Content-Type" => "application/json")))), true)) && !empty($goo_gl["id"]) && is_string($goo_gl_url = $goo_gl["id"]) && stripos($goo_gl_url, "http") === 0)
269
+ return /* Google API: <http://code.google.com/apis/urlshortener/v1/getting_started.html>. */ ($shorter_url = $goo_gl_url);
270
 
271
  else if /* Try backups? This way we can still shorten the URL with a backup. */($try_backups && count($apis) > 1)
272
 
includes/classes/utils-users.inc.php CHANGED
@@ -58,7 +58,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_users"))
58
  * @since 3.5
59
  *
60
  * @param str $subscr_or_txn_id Either a Paid Subscr. ID, or a Paid Transaction ID.
61
- * @param str $os0 Optional. A second lookup parameter, usually the `os0` value for PayPal® integrations.
62
  * @return str|bool The Custom String value on success, else false on failure.
63
  */
64
  public static function get_user_custom_with ($subscr_or_txn_id = FALSE, $os0 = FALSE)
@@ -67,14 +67,14 @@ if (!class_exists ("c_ws_plugin__s2member_utils_users"))
67
 
68
  if /* This case includes some additional routines that can use the ``$os0`` value. */ ($subscr_or_txn_id && $os0)
69
  {
70
- if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE (`meta_key` = '" . $wpdb->prefix . "s2member_subscr_id' OR `meta_key` = '" . $wpdb->prefix . "s2member_first_payment_txn_id') AND (`meta_value` = '" . $wpdb->escape ($subscr_or_txn_id) . "' OR `meta_value` = '" . $wpdb->escape ($os0) . "') LIMIT 1"))
71
- || ($q = $wpdb->get_row ("SELECT `ID` AS `user_id` FROM `" . $wpdb->users . "` WHERE `ID` = '" . $wpdb->escape ($os0) . "' LIMIT 1")))
72
  if (($custom = get_user_option ("s2member_custom", $q->user_id)))
73
  return $custom;
74
  }
75
  else if /* Otherwise, if all we have is a Subscr./Txn. ID value. */ ($subscr_or_txn_id)
76
  {
77
- if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE (`meta_key` = '" . $wpdb->prefix . "s2member_subscr_id' OR `meta_key` = '" . $wpdb->prefix . "s2member_first_payment_txn_id') AND `meta_value` = '" . $wpdb->escape ($subscr_or_txn_id) . "' LIMIT 1")))
78
  if (($custom = get_user_option ("s2member_custom", $q->user_id)))
79
  return $custom;
80
  }
@@ -89,8 +89,8 @@ if (!class_exists ("c_ws_plugin__s2member_utils_users"))
89
  * @since 3.5
90
  *
91
  * @param str $subscr_or_txn_id Either a Paid Subscr. ID, or a Paid Transaction ID.
92
- * @param str $os0 Optional. A second lookup parameter, usually the `os0` value for PayPal® integrations.
93
- * @return int|bool A WordPress® User ID on success, else false on failure.
94
  */
95
  public static function get_user_id_with ($subscr_or_txn_id = FALSE, $os0 = FALSE)
96
  {
@@ -98,13 +98,13 @@ if (!class_exists ("c_ws_plugin__s2member_utils_users"))
98
 
99
  if /* This case includes some additional routines that can use the ``$os0`` value. */($subscr_or_txn_id && $os0)
100
  {
101
- if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE (`meta_key` = '" . $wpdb->prefix . "s2member_subscr_id' OR `meta_key` = '" . $wpdb->prefix . "s2member_first_payment_txn_id') AND (`meta_value` = '" . $wpdb->escape ($subscr_or_txn_id) . "' OR `meta_value` = '" . $wpdb->escape ($os0) . "') LIMIT 1"))
102
- || ($q = $wpdb->get_row ("SELECT `ID` AS `user_id` FROM `" . $wpdb->users . "` WHERE `ID` = '" . $wpdb->escape ($os0) . "' LIMIT 1")))
103
  return $q->user_id;
104
  }
105
  else if /* Otherwise, if all we have is a Subscr./Txn. ID value. */ ($subscr_or_txn_id)
106
  {
107
- if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE (`meta_key` = '" . $wpdb->prefix . "s2member_subscr_id' OR `meta_key` = '" . $wpdb->prefix . "s2member_first_payment_txn_id') AND `meta_value` = '" . $wpdb->escape ($subscr_or_txn_id) . "' LIMIT 1")))
108
  return $q->user_id;
109
  }
110
  return /* Otherwise, return false. */ false;
@@ -118,7 +118,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_users"))
118
  * @since 3.5
119
  *
120
  * @param str $subscr_or_txn_id Either a Paid Subscr. ID, or a Paid Transaction ID.
121
- * @param str $os0 Optional. A second lookup parameter, usually the `os0` value for PayPal® integrations.
122
  * @return int|bool A User's Email Address on success, else false on failure.
123
  */
124
  public static function get_user_email_with ($subscr_or_txn_id = FALSE, $os0 = FALSE)
@@ -127,14 +127,14 @@ if (!class_exists ("c_ws_plugin__s2member_utils_users"))
127
 
128
  if /* This case includes some additional routines that can use the ``$os0`` value. */($subscr_or_txn_id && $os0)
129
  {
130
- if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE (`meta_key` = '" . $wpdb->prefix . "s2member_subscr_id' OR `meta_key` = '" . $wpdb->prefix . "s2member_first_payment_txn_id') AND (`meta_value` = '" . $wpdb->escape ($subscr_or_txn_id) . "' OR `meta_value` = '" . $wpdb->escape ($os0) . "') LIMIT 1"))
131
- || ($q = $wpdb->get_row ("SELECT `ID` AS `user_id` FROM `" . $wpdb->users . "` WHERE `ID` = '" . $wpdb->escape ($os0) . "' LIMIT 1")))
132
  if (is_object ($user = new WP_User ($q->user_id)) && !empty ($user->ID) && ($email = $user->user_email))
133
  return $email;
134
  }
135
  else if /* Otherwise, if all we have is a Subscr./Txn. ID value. */($subscr_or_txn_id)
136
  {
137
- if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE (`meta_key` = '" . $wpdb->prefix . "s2member_subscr_id' OR `meta_key` = '" . $wpdb->prefix . "s2member_first_payment_txn_id') AND `meta_value` = '" . $wpdb->escape ($subscr_or_txn_id) . "' LIMIT 1")))
138
  if (is_object ($user = new WP_User ($q->user_id)) && !empty ($user->ID) && ($email = $user->user_email))
139
  return $email;
140
  }
@@ -148,7 +148,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_users"))
148
  * @package s2Member\Utilities
149
  * @since 3.5
150
  *
151
- * @param int|str $user_id Optional. A numeric WordPress® User ID.
152
  * @param str $subscr_id Optional. Can be used instead of passing in a ``$user_id``.
153
  * If ``$subscr_id`` is passed in, it has to match the one found inside the resulting IPN Signup Vars collected by this routine.
154
  * If neither of these parameters are passed in, the current User is assumed instead, obtained through ``wp_get_current_user()``.
@@ -174,7 +174,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_users"))
174
  * @since 110912
175
  *
176
  * @param str $var Required. The requested Signup Var.
177
- * @param int|str $user_id Optional. A numeric WordPress® User ID.
178
  * @param str $subscr_id Optional. Can be used instead of passing in a ``$user_id``.
179
  * If ``$subscr_id`` is passed in, it has to match the one found inside the resulting IPN Signup Vars collected by this routine.
180
  * If neither of these parameters are passed in, the current User is assumed instead, obtained through ``wp_get_current_user()``.
@@ -200,7 +200,7 @@ if (!class_exists ("c_ws_plugin__s2member_utils_users"))
200
  *
201
  * @param obj $user Optional. A `WP_User` object.
202
  * In order to check the current User, you must call this function with no arguments/parameters.
203
- * @return int|str|bool If possible, the User's Paid Subscr. ID, else their WordPress® User ID, else false.
204
  */
205
  public static function get_user_subscr_or_wp_id ($user = FALSE)
206
  {
@@ -214,14 +214,14 @@ if (!class_exists ("c_ws_plugin__s2member_utils_users"))
214
  /**
215
  * Determines whether or not a Username/Email is already in the database.
216
  *
217
- * Returns the WordPress® User ID if they exist.
218
  *
219
  * @package s2Member\Utilities
220
  * @since 3.5
221
  *
222
  * @param str $user_login A User's Username.
223
  * @param str $user_email A User's Email Address.
224
- * @return int|bool If exists, a WordPress® User ID, else false.
225
  */
226
  public static function user_login_email_exists ($user_login = FALSE, $user_email = FALSE)
227
  {
@@ -229,22 +229,22 @@ if (!class_exists ("c_ws_plugin__s2member_utils_users"))
229
 
230
  if /* Only if we have both of these. */ ($user_login && $user_email)
231
  if (($user_id = $wpdb->get_var ("SELECT `ID` FROM `" . $wpdb->users . "` WHERE `user_login` LIKE '" . esc_sql (like_escape ($user_login)) . "' AND `user_email` LIKE '" . esc_sql (like_escape ($user_email)) . "' LIMIT 1")))
232
- return /* Return the associated WordPress® ID. */$user_id;
233
 
234
  return /* Else return false. */false;
235
  }
236
  /**
237
  * Determines whether or not a Username/Email is already in the database for this Blog.
238
  *
239
- * Returns the WordPress® User ID if they exist.
240
  *
241
  * @package s2Member\Utilities
242
  * @since 3.5
243
  *
244
  * @param str $user_login A User's Username.
245
  * @param str $user_email A User's Email Address.
246
- * @param int|str $blog_id A numeric WordPress® Blog ID.
247
- * @return int|bool If exists *(but not on Blog)*, a WordPress® User ID, else false.
248
  */
249
  public static function ms_user_login_email_exists_but_not_on_blog ($user_login = FALSE, $user_email = FALSE, $blog_id = FALSE)
250
  {
@@ -259,15 +259,15 @@ if (!class_exists ("c_ws_plugin__s2member_utils_users"))
259
  *
260
  * This is an alias for: `c_ws_plugin__s2member_utils_users::ms_user_login_email_exists_but_not_on_blog()`.
261
  *
262
- * Returns the WordPress® User ID if they exist.
263
  *
264
  * @package s2Member\Utilities
265
  * @since 3.5
266
  *
267
  * @param str $user_login A User's Username.
268
  * @param str $user_email A User's Email Address.
269
- * @param int|str $blog_id A numeric WordPress® Blog ID.
270
- * @return int|bool If exists *(but not on Blog)*, a WordPress® User ID, else false.
271
  */
272
  public static function ms_user_login_email_can_join_blog ($user_login = FALSE, $user_email = FALSE, $blog_id = FALSE)
273
  {
58
  * @since 3.5
59
  *
60
  * @param str $subscr_or_txn_id Either a Paid Subscr. ID, or a Paid Transaction ID.
61
+ * @param str $os0 Optional. A second lookup parameter, usually the `os0` value for PayPal integrations.
62
  * @return str|bool The Custom String value on success, else false on failure.
63
  */
64
  public static function get_user_custom_with ($subscr_or_txn_id = FALSE, $os0 = FALSE)
67
 
68
  if /* This case includes some additional routines that can use the ``$os0`` value. */ ($subscr_or_txn_id && $os0)
69
  {
70
+ if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE (`meta_key` = '" . $wpdb->prefix . "s2member_subscr_id' OR `meta_key` = '" . $wpdb->prefix . "s2member_first_payment_txn_id') AND (`meta_value` = '" . esc_sql ($subscr_or_txn_id) . "' OR `meta_value` = '" . esc_sql ($os0) . "') LIMIT 1"))
71
+ || ($q = $wpdb->get_row ("SELECT `ID` AS `user_id` FROM `" . $wpdb->users . "` WHERE `ID` = '" . esc_sql ($os0) . "' LIMIT 1")))
72
  if (($custom = get_user_option ("s2member_custom", $q->user_id)))
73
  return $custom;
74
  }
75
  else if /* Otherwise, if all we have is a Subscr./Txn. ID value. */ ($subscr_or_txn_id)
76
  {
77
+ if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE (`meta_key` = '" . $wpdb->prefix . "s2member_subscr_id' OR `meta_key` = '" . $wpdb->prefix . "s2member_first_payment_txn_id') AND `meta_value` = '" . esc_sql ($subscr_or_txn_id) . "' LIMIT 1")))
78
  if (($custom = get_user_option ("s2member_custom", $q->user_id)))
79
  return $custom;
80
  }
89
  * @since 3.5
90
  *
91
  * @param str $subscr_or_txn_id Either a Paid Subscr. ID, or a Paid Transaction ID.
92
+ * @param str $os0 Optional. A second lookup parameter, usually the `os0` value for PayPal integrations.
93
+ * @return int|bool A WordPress User ID on success, else false on failure.
94
  */
95
  public static function get_user_id_with ($subscr_or_txn_id = FALSE, $os0 = FALSE)
96
  {
98
 
99
  if /* This case includes some additional routines that can use the ``$os0`` value. */($subscr_or_txn_id && $os0)
100
  {
101
+ if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE (`meta_key` = '" . $wpdb->prefix . "s2member_subscr_id' OR `meta_key` = '" . $wpdb->prefix . "s2member_first_payment_txn_id') AND (`meta_value` = '" . esc_sql ($subscr_or_txn_id) . "' OR `meta_value` = '" . esc_sql ($os0) . "') LIMIT 1"))
102
+ || ($q = $wpdb->get_row ("SELECT `ID` AS `user_id` FROM `" . $wpdb->users . "` WHERE `ID` = '" . esc_sql ($os0) . "' LIMIT 1")))
103
  return $q->user_id;
104
  }
105
  else if /* Otherwise, if all we have is a Subscr./Txn. ID value. */ ($subscr_or_txn_id)
106
  {
107
+ if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE (`meta_key` = '" . $wpdb->prefix . "s2member_subscr_id' OR `meta_key` = '" . $wpdb->prefix . "s2member_first_payment_txn_id') AND `meta_value` = '" . esc_sql ($subscr_or_txn_id) . "' LIMIT 1")))
108
  return $q->user_id;
109
  }
110
  return /* Otherwise, return false. */ false;
118
  * @since 3.5
119
  *
120
  * @param str $subscr_or_txn_id Either a Paid Subscr. ID, or a Paid Transaction ID.
121
+ * @param str $os0 Optional. A second lookup parameter, usually the `os0` value for PayPal integrations.
122
  * @return int|bool A User's Email Address on success, else false on failure.
123
  */
124
  public static function get_user_email_with ($subscr_or_txn_id = FALSE, $os0 = FALSE)
127
 
128
  if /* This case includes some additional routines that can use the ``$os0`` value. */($subscr_or_txn_id && $os0)
129
  {
130
+ if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE (`meta_key` = '" . $wpdb->prefix . "s2member_subscr_id' OR `meta_key` = '" . $wpdb->prefix . "s2member_first_payment_txn_id') AND (`meta_value` = '" . esc_sql ($subscr_or_txn_id) . "' OR `meta_value` = '" . esc_sql ($os0) . "') LIMIT 1"))
131
+ || ($q = $wpdb->get_row ("SELECT `ID` AS `user_id` FROM `" . $wpdb->users . "` WHERE `ID` = '" . esc_sql ($os0) . "' LIMIT 1")))
132
  if (is_object ($user = new WP_User ($q->user_id)) && !empty ($user->ID) && ($email = $user->user_email))
133
  return $email;
134
  }
135
  else if /* Otherwise, if all we have is a Subscr./Txn. ID value. */($subscr_or_txn_id)
136
  {
137
+ if (($q = $wpdb->get_row ("SELECT `user_id` FROM `" . $wpdb->usermeta . "` WHERE (`meta_key` = '" . $wpdb->prefix . "s2member_subscr_id' OR `meta_key` = '" . $wpdb->prefix . "s2member_first_payment_txn_id') AND `meta_value` = '" . esc_sql ($subscr_or_txn_id) . "' LIMIT 1")))
138
  if (is_object ($user = new WP_User ($q->user_id)) && !empty ($user->ID) && ($email = $user->user_email))
139
  return $email;
140
  }
148
  * @package s2Member\Utilities
149
  * @since 3.5
150
  *
151
+ * @param int|str $user_id Optional. A numeric WordPress User ID.
152
  * @param str $subscr_id Optional. Can be used instead of passing in a ``$user_id``.
153
  * If ``$subscr_id`` is passed in, it has to match the one found inside the resulting IPN Signup Vars collected by this routine.
154
  * If neither of these parameters are passed in, the current User is assumed instead, obtained through ``wp_get_current_user()``.
174
  * @since 110912
175
  *
176
  * @param str $var Required. The requested Signup Var.
177
+ * @param int|str $user_id Optional. A numeric WordPress User ID.
178
  * @param str $subscr_id Optional. Can be used instead of passing in a ``$user_id``.
179
  * If ``$subscr_id`` is passed in, it has to match the one found inside the resulting IPN Signup Vars collected by this routine.
180
  * If neither of these parameters are passed in, the current User is assumed instead, obtained through ``wp_get_current_user()``.
200
  *
201
  * @param obj $user Optional. A `WP_User` object.
202
  * In order to check the current User, you must call this function with no arguments/parameters.
203
+ * @return int|str|bool If possible, the User's Paid Subscr. ID, else their WordPress User ID, else false.
204
  */
205
  public static function get_user_subscr_or_wp_id ($user = FALSE)
206
  {
214
  /**
215
  * Determines whether or not a Username/Email is already in the database.
216
  *
217
+ * Returns the WordPress User ID if they exist.
218
  *
219
  * @package s2Member\Utilities
220
  * @since 3.5
221
  *
222
  * @param str $user_login A User's Username.
223
  * @param str $user_email A User's Email Address.
224
+ * @return int|bool If exists, a WordPress User ID, else false.
225
  */
226
  public static function user_login_email_exists ($user_login = FALSE, $user_email = FALSE)
227
  {
229
 
230
  if /* Only if we have both of these. */ ($user_login && $user_email)
231
  if (($user_id = $wpdb->get_var ("SELECT `ID` FROM `" . $wpdb->users . "` WHERE `user_login` LIKE '" . esc_sql (like_escape ($user_login)) . "' AND `user_email` LIKE '" . esc_sql (like_escape ($user_email)) . "' LIMIT 1")))
232
+ return /* Return the associated WordPress ID. */$user_id;
233
 
234
  return /* Else return false. */false;
235
  }
236
  /**
237
  * Determines whether or not a Username/Email is already in the database for this Blog.
238
  *
239
+ * Returns the WordPress User ID if they exist.
240
  *
241
  * @package s2Member\Utilities
242
  * @since 3.5
243
  *
244
  * @param str $user_login A User's Username.
245
  * @param str $user_email A User's Email Address.
246
+ * @param int|str $blog_id A numeric WordPress Blog ID.
247
+ * @return int|bool If exists *(but not on Blog)*, a WordPress User ID, else false.
248
  */
249
  public static function ms_user_login_email_exists_but_not_on_blog ($user_login = FALSE, $user_email = FALSE, $blog_id = FALSE)
250
  {
259
  *
260
  * This is an alias for: `c_ws_plugin__s2member_utils_users::ms_user_login_email_exists_but_not_on_blog()`.
261
  *
262
+ * Returns the WordPress User ID if they exist.
263
  *
264
  * @package s2Member\Utilities
265
  * @since 3.5
266
  *
267
  * @param str $user_login A User's Username.
268
  * @param str $user_email A User's Email Address.
269
+ * @param int|str $blog_id A numeric WordPress Blog ID.
270
+ * @return int|bool If exists *(but not on Blog)*, a WordPress User ID, else false.
271
  */
272
  public static function ms_user_login_email_can_join_blog ($user_login = FALSE, $user_email = FALSE, $blog_id = FALSE)
273
  {
includes/classes/wp-footer.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * WordPress® footer code.
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_wp_footer"))
21
  {
22
  /**
23
- * WordPress® footer code.
24
  *
25
  * @package s2Member\WP_Footer
26
  * @since 110524RC
1
  <?php
2
  /**
3
+ * WordPress footer code.
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_wp_footer"))
21
  {
22
  /**
23
+ * WordPress footer code.
24
  *
25
  * @package s2Member\WP_Footer
26
  * @since 110524RC
includes/codes.inc.php CHANGED
@@ -17,7 +17,7 @@
17
  if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
18
  exit ("Do not access this file directly.");
19
  /*
20
- Add WordPress® Editor Shortcodes.
21
  */
22
  add_shortcode ("s2Key", "c_ws_plugin__s2member_sc_keys::sc_get_key");
23
  add_shortcode ("s2Get", "c_ws_plugin__s2member_sc_gets::sc_get_details");
17
  if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
18
  exit ("Do not access this file directly.");
19
  /*
20
+ Add WordPress Editor Shortcodes.
21
  */
22
  add_shortcode ("s2Key", "c_ws_plugin__s2member_sc_keys::sc_get_key");
23
  add_shortcode ("s2Get", "c_ws_plugin__s2member_sc_gets::sc_get_details");
includes/externals/mailchimp/nc-mcapi.inc.php CHANGED
@@ -1,8 +1,8 @@
1
  <?php
2
  /**
3
- * MailChimp® API Class.
4
  *
5
- * Copyright {@link http://www.mailchimp.com/ MailChimp®}.
6
  *
7
  * Modified by {@link http://www.websharks-inc.com/ WebSharks, Inc.}.
8
  * Uses a custom class name to avoid conflicts with other instances.
1
  <?php
2
  /**
3
+ * MailChimp API Class.
4
  *
5
+ * Copyright {@link http://www.mailchimp.com/ MailChimp}.
6
  *
7
  * Modified by {@link http://www.websharks-inc.com/ WebSharks, Inc.}.
8
  * Uses a custom class name to avoid conflicts with other instances.
includes/externals/markdown/nc-markdown.inc.php CHANGED
@@ -6,10 +6,10 @@
6
  * Original Markdown. Copyright {@link http://daringfireball.net/projects/markdown/ John Gruber}.
7
  *
8
  * Modified by {@link http://www.websharks-inc.com/ WebSharks, Inc.}.
9
- * Excludes WordPress® and all other interfaces.
10
  * Uses a custom class name and interface.
11
  *
12
- * This file is included with all WordPress® themes/plugins by WebSharks, Inc.
13
  *
14
  * @package WebSharks\Xtnls\Markdown
15
  * @since x.xx
6
  * Original Markdown. Copyright {@link http://daringfireball.net/projects/markdown/ John Gruber}.
7
  *
8
  * Modified by {@link http://www.websharks-inc.com/ WebSharks, Inc.}.
9
+ * Excludes WordPress and all other interfaces.
10
  * Uses a custom class name and interface.
11
  *
12
+ * This file is included with all WordPress themes/plugins by WebSharks, Inc.
13
  *
14
  * @package WebSharks\Xtnls\Markdown
15
  * @since x.xx
includes/functions/api-functions.inc.php CHANGED
@@ -19,7 +19,7 @@ if(realpath(__FILE__) === realpath($_SERVER["SCRIPT_FILENAME"]))
19
  /**
20
  * Conditional to determine if the current User is NOT logged in.
21
  *
22
- * Counterpart {@link http://codex.wordpress.org/Function_Reference/is_user_logged_in is_user_logged_in()} already exists in the WordPress® core.
23
  *
24
  * ———— Code Sample Using Both Functions ————
25
  * ```
@@ -59,7 +59,7 @@ if(!function_exists("is_user_not_logged_in"))
59
  /**
60
  * Conditional to determine if a specific User is/has a specific Role.
61
  *
62
- * Another function {@link http://codex.wordpress.org/Function_Reference/user_can user_can()} already exists in the WordPress® core.
63
  *
64
  * ———— Code Sample Using Both Functions ————
65
  * ```
@@ -100,15 +100,15 @@ if(!function_exists("is_user_not_logged_in"))
100
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
101
  * o A public Visitor will have NO access to protected content.
102
  *
103
- * WordPress® Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
104
- * WordPress® Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
105
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
106
  *
107
  * @package s2Member\API_Functions
108
  * @since 110524RC
109
  *
110
- * @param int|str $id A numeric WordPress® User ID.
111
- * @param str $role A WordPress® Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
112
  * @return bool True if the specific User is/has the specified Role, else false.
113
  *
114
  * @see s2Member\API_Functions\user_is()
@@ -145,7 +145,7 @@ if(!function_exists("user_is"))
145
  /**
146
  * Conditional to determine if a specific User is/does NOT have a specific Role.
147
  *
148
- * Another function {@link http://codex.wordpress.org/Function_Reference/user_can user_can()} already exists in the WordPress® core.
149
  *
150
  * ———— Code Sample Using Three Functions ————
151
  * ```
@@ -185,15 +185,15 @@ if(!function_exists("user_is"))
185
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
186
  * o A public Visitor will have NO access to protected content.
187
  *
188
- * WordPress® Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
189
- * WordPress® Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
190
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
191
  *
192
  * @package s2Member\API_Functions
193
  * @since 110524RC
194
  *
195
- * @param int|str $id A numeric WordPress® User ID.
196
- * @param str $role A WordPress® Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
197
  * @return bool True if the specific User is/does NOT have the specified Role, else false.
198
  *
199
  * @see s2Member\API_Functions\user_is()
@@ -222,7 +222,7 @@ if(!function_exists("user_is_not"))
222
  /**
223
  * Conditional to determine if the current User is/has a specific Role.
224
  *
225
- * Another function {@link http://codex.wordpress.org/Function_Reference/current_user_can current_user_can()} already exists in the WordPress® core.
226
  *
227
  * ———— Code Sample Using Both Functions ————
228
  * ```
@@ -263,14 +263,14 @@ if(!function_exists("user_is_not"))
263
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
264
  * o A public Visitor will have NO access to protected content.
265
  *
266
- * WordPress® Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
267
- * WordPress® Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
268
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
269
  *
270
  * @package s2Member\API_Functions
271
  * @since 3.5
272
  *
273
- * @param str $role A WordPress® Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
274
  * @return bool True if the current User is/has the specified Role, else false.
275
  *
276
  * @see s2Member\API_Functions\user_is()
@@ -307,7 +307,7 @@ if(!function_exists("current_user_is"))
307
  /**
308
  * Conditional to determine if the current User is/does NOT have a specific Role.
309
  *
310
- * Another function {@link http://codex.wordpress.org/Function_Reference/current_user_can current_user_can()} already exists in the WordPress® core.
311
  *
312
  * ———— Code Sample Using Three Functions ————
313
  * ```
@@ -347,14 +347,14 @@ if(!function_exists("current_user_is"))
347
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
348
  * o A public Visitor will have NO access to protected content.
349
  *
350
- * WordPress® Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
351
- * WordPress® Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
352
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
353
  *
354
  * @package s2Member\API_Functions
355
  * @since 3.5
356
  *
357
- * @param str $role A WordPress® Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
358
  * @return bool True if the current User is/does NOT have the specified Role, else false.
359
  *
360
  * @see s2Member\API_Functions\user_is()
@@ -383,7 +383,7 @@ if(!function_exists("current_user_is_not"))
383
  /**
384
  * Conditional to determine if the current User is/has a specific Role, on a specific Blog within a Multisite Network.
385
  *
386
- * Another function {@link http://codex.wordpress.org/Function_Reference/current_user_can_for_blog current_user_can_for_blog()} already exists in the WordPress® core.
387
  *
388
  * ———— Code Sample Using Three Functions ————
389
  * ```
@@ -429,15 +429,15 @@ if(!function_exists("current_user_is_not"))
429
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
430
  * o A public Visitor will have NO access to protected content.
431
  *
432
- * WordPress® Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
433
- * WordPress® Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
434
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
435
  *
436
  * @package s2Member\API_Functions
437
  * @since 3.5
438
  *
439
- * @param int|str $blog_id A WordPress® Blog ID *(must be numeric)*.
440
- * @param str $role A WordPress® Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
441
  * @return bool True if the current User is/has the specified Role, on the specified Blog, else false.
442
  *
443
  * @see s2Member\API_Functions\user_is()
@@ -474,7 +474,7 @@ if(!function_exists("current_user_is_for_blog"))
474
  /**
475
  * Conditional to determine if the current User is/does NOT have a specific Role, on a specific Blog within a Multisite Network.
476
  *
477
- * Another function {@link http://codex.wordpress.org/Function_Reference/current_user_can_for_blog current_user_can_for_blog()} already exists in the WordPress® core.
478
  *
479
  * ———— Code Sample Using Three Functions ————
480
  * ```
@@ -508,15 +508,15 @@ if(!function_exists("current_user_is_for_blog"))
508
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
509
  * o A public Visitor will have NO access to protected content.
510
  *
511
- * WordPress® Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
512
- * WordPress® Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
513
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
514
  *
515
  * @package s2Member\API_Functions
516
  * @since 3.5
517
  *
518
- * @param int|str $blog_id A WordPress® Blog ID *(must be numeric)*.
519
- * @param str $role A WordPress® Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
520
  * @return bool True if the current User is/does NOT have the specified Role, on the specified Blog, else false.
521
  *
522
  * @see s2Member\API_Functions\user_is()
@@ -545,7 +545,7 @@ if(!function_exists("current_user_is_not_for_blog"))
545
  /**
546
  * Conditional to determine if a specific User does NOT have a specific Capability or Role.
547
  *
548
- * Another function {@link http://codex.wordpress.org/Function_Reference/user_can user_can()} already exists in the WordPress® core.
549
  *
550
  * ———— Code Sample Using Both Functions ————
551
  * ```
@@ -577,15 +577,15 @@ if(!function_exists("current_user_is_not_for_blog"))
577
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
578
  * o A public Visitor will have NO access to protected content.
579
  *
580
- * WordPress® Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
581
- * WordPress® Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
582
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
583
  *
584
  * @package s2Member\API_Functions
585
  * @since 3.5
586
  *
587
- * @param int|str $id A numeric WordPress® User ID.
588
- * @param str $capability A WordPress® Capability ID *( i.e. `access_s2member_level[0-9]+`, `access_s2member_ccap_music` )*.
589
  * @return bool True if the specific User does NOT have the specified Capability or Role, else false.
590
  *
591
  * @see s2Member\API_Functions\user_is()
@@ -614,7 +614,7 @@ if(!function_exists("user_cannot"))
614
  /**
615
  * Conditional to determine if the current User does NOT have a specific Capability or Role.
616
  *
617
- * Another function {@link http://codex.wordpress.org/Function_Reference/current_user_can current_user_can()} already exists in the WordPress® core.
618
  *
619
  * ———— Code Sample Using Both Functions ————
620
  * ```
@@ -646,14 +646,14 @@ if(!function_exists("user_cannot"))
646
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
647
  * o A public Visitor will have NO access to protected content.
648
  *
649
- * WordPress® Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
650
- * WordPress® Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
651
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
652
  *
653
  * @package s2Member\API_Functions
654
  * @since 3.5
655
  *
656
- * @param str $capability A WordPress® Capability ID *( i.e. `access_s2member_level[0-9]+`, `access_s2member_ccap_music` )*.
657
  * Or a Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
658
  * @return bool True if the current User does NOT have the specified Capability or Role, else false.
659
  *
@@ -683,7 +683,7 @@ if(!function_exists("current_user_cannot"))
683
  /**
684
  * Conditional to determine if the current User does NOT have a specific Capability or Role, on a specific Blog within a Multisite Network.
685
  *
686
- * Another function {@link http://codex.wordpress.org/Function_Reference/current_user_can_for_blog current_user_can_for_blog()} already exists in the WordPress® core.
687
  *
688
  * ———— Code Sample Using Both Functions ————
689
  * ```
@@ -715,15 +715,15 @@ if(!function_exists("current_user_cannot"))
715
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
716
  * o A public Visitor will have NO access to protected content.
717
  *
718
- * WordPress® Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
719
- * WordPress® Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
720
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
721
  *
722
  * @package s2Member\API_Functions
723
  * @since 3.5
724
  *
725
- * @param int|str $blog_id A WordPress® Blog ID *(must be numeric)*.
726
- * @param str $capability A WordPress® Capability ID *( i.e. `access_s2member_level[0-9]+`, `access_s2member_ccap_music` )*.
727
  * Or a Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
728
  * @return bool True if the current User does NOT have the specified Capability or Role, else false.
729
  *
@@ -758,7 +758,7 @@ if(!function_exists("current_user_cannot_for_blog"))
758
  *
759
  * **Parameter $what (int|str Optional).**
760
  * Defaults to the current $post ID when called from within {@link http://codex.wordpress.org/The_Loop The Loop}.
761
- * If passed in, this should be a WordPress® Category ID, Tag ID, Post ID, or Page ID. Or a full URL. A URI is also fine.
762
  *
763
  * o If you pass in an ID, s2Member will check everything, including your configured URI Restrictions against the ID.
764
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
@@ -823,7 +823,7 @@ if(!function_exists("current_user_cannot_for_blog"))
823
  * @since 3.5
824
  *
825
  * @param int|str $what Optional. Defaults to the current $post ID when called from within {@link http://codex.wordpress.org/The_Loop The Loop}.
826
- * If passed in, this should be a WordPress® Category ID, Tag ID, Post ID, or Page ID. Or a full URL. A URI is also fine.
827
  * @param str $type Optional. One of `category`, `tag`, `post`, `page`, `singular` or `uri`. Defaults to `singular` *(i.e. a Post or Page)*.
828
  * @param bool $check_user Optional. Consider the current User? Defaults to false.
829
  * @return array|bool A non-empty array *(meaning true)*, or false if the content is not protected *(i.e. available publicly)*.
@@ -890,7 +890,7 @@ if(!function_exists("is_protected_by_s2member"))
890
  *
891
  * **Parameter $what (int|str Optional).**
892
  * Defaults to the current $post ID when called from within {@link http://codex.wordpress.org/The_Loop The Loop}.
893
- * If passed in, this should be a WordPress® Category ID, Tag ID, Post ID, or Page ID. Or a full URL. A URI is also fine.
894
  *
895
  * o If you pass in an ID, s2Member will check everything, including your configured URI Restrictions against the ID.
896
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
@@ -948,7 +948,7 @@ if(!function_exists("is_protected_by_s2member"))
948
  * @since 3.5
949
  *
950
  * @param int|str $what Optional. Defaults to the current $post ID when called from within {@link http://codex.wordpress.org/The_Loop The Loop}.
951
- * If passed in, this should be a WordPress® Category ID, Tag ID, Post ID, or Page ID. Or a full URL. A URI is also fine.
952
  * @param str $type Optional. One of `category`, `tag`, `post`, `page`, `singular` or `uri`. Defaults to `singular` *(i.e. a Post or Page)*.
953
  * @return bool True if the current User IS permitted, else false if the content is NOT available to the current User;
954
  * based on your configuration of s2Member, and based on the current User's Role/Capabilities.
@@ -1007,7 +1007,7 @@ if(!function_exists("is_permitted_by_s2member"))
1007
  *
1008
  * ———— Extra Detail On Function Parameters ————
1009
  *
1010
- * **Parameter $cat_id (int Required).** This should be a WordPress® Category ID.
1011
  *
1012
  * o s2Member will check everything, including your configured URI Restrictions against the ID.
1013
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
@@ -1038,7 +1038,7 @@ if(!function_exists("is_permitted_by_s2member"))
1038
  * @package s2Member\API_Functions
1039
  * @since 3.5
1040
  *
1041
- * @param int $cat_id Required. This should be a WordPress® Category ID.
1042
  * @param bool $check_user Optional. Consider the current User? Defaults to false.
1043
  * @return array|bool A non-empty array *(meaning true)*, or false if the Category is not protected *(i.e. available publicly)*.
1044
  * When/if the Category IS protected, the return array will include one of these keys ``["s2member_(level|sp|ccap)_req"]``
@@ -1085,7 +1085,7 @@ if(!function_exists("is_category_protected_by_s2member"))
1085
  *
1086
  * ———— Extra Detail On Function Parameters ————
1087
  *
1088
- * **Parameter $cat_id (int Required).** This should be a WordPress® Category ID.
1089
  *
1090
  * o s2Member will check everything, including your configured URI Restrictions against the ID.
1091
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
@@ -1109,7 +1109,7 @@ if(!function_exists("is_category_protected_by_s2member"))
1109
  * @package s2Member\API_Functions
1110
  * @since 3.5
1111
  *
1112
- * @param int $cat_id Required. This should be a WordPress® Category ID.
1113
  * @return bool True if the current User IS permitted, else false if the Category is NOT available to the current User;
1114
  * based on your configuration of s2Member, and based on the current User's Role/Capabilities.
1115
  *
@@ -1150,7 +1150,7 @@ if(!function_exists("is_category_permitted_by_s2member"))
1150
  *
1151
  * ———— Extra Detail On Function Parameters ————
1152
  *
1153
- * **Parameter $tag_id_slug_or_name (int|str Required).** This should be a WordPress® Tag ID, Tag Slug, or Tag Name.
1154
  *
1155
  * o s2Member will check everything, including your configured URI Restrictions against the ID, Slug, or Name.
1156
  * In other words, s2Member is capable of determining a URI based on the ID, or Slug, or Name that you pass in.
@@ -1194,7 +1194,7 @@ if(!function_exists("is_category_permitted_by_s2member"))
1194
  * @package s2Member\API_Functions
1195
  * @since 3.5
1196
  *
1197
- * @param int|str $tag_id_slug_or_name Required. This should be a WordPress® Tag ID, Tag Slug, or Tag Name.
1198
  * @param bool $check_user Optional. Consider the current User? Defaults to false.
1199
  * @return array|bool A non-empty array *(meaning true)*, or false if the Tag is not protected *(i.e. available publicly)*.
1200
  * When/if the Tag IS protected, the return array will include one of these keys ``["s2member_(level|sp|ccap)_req"]``
@@ -1241,7 +1241,7 @@ if(!function_exists("is_tag_protected_by_s2member"))
1241
  *
1242
  * ———— Extra Detail On Function Parameters ————
1243
  *
1244
- * **Parameter $tag_id_slug_or_name (int|str Required).** This should be a WordPress® Tag ID, Tag Slug, or Tag Name.
1245
  *
1246
  * o s2Member will check everything, including your configured URI Restrictions against the ID, or Slug, or Name.
1247
  * In other words, s2Member is capable of determining a URI based on the ID, or Slug, or Name that you pass in.
@@ -1278,7 +1278,7 @@ if(!function_exists("is_tag_protected_by_s2member"))
1278
  * @package s2Member\API_Functions
1279
  * @since 3.5
1280
  *
1281
- * @param int|str $tag_id_slug_or_name Required. This should be a WordPress® Tag ID, Tag Slug, or Tag Name.
1282
  * @return bool True if the current User IS permitted, else false if the Tag is NOT available to the current User;
1283
  * based on your configuration of s2Member, and based on the current User's Role/Capabilities.
1284
  *
@@ -1319,7 +1319,7 @@ if(!function_exists("is_tag_permitted_by_s2member"))
1319
  *
1320
  * ———— Extra Detail On Function Parameters ————
1321
  *
1322
- * **Parameter $post_id (int Required).** This should be a WordPress® Post ID, or a Custom Post Type ID.
1323
  *
1324
  * o s2Member will check everything, including your configured URI Restrictions against the ID.
1325
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
@@ -1350,7 +1350,7 @@ if(!function_exists("is_tag_permitted_by_s2member"))
1350
  * @package s2Member\API_Functions
1351
  * @since 3.5
1352
  *
1353
- * @param int $post_id Required. This should be a WordPress® Post ID, or a Custom Post Type ID.
1354
  * @param bool $check_user Optional. Consider the current User? Defaults to false.
1355
  * @return array|bool A non-empty array *(meaning true)*, or false if the Post is not protected *(i.e. available publicly)*.
1356
  * When/if the Post IS protected, the return array will include one of these keys ``["s2member_(level|sp|ccap)_req"]``
@@ -1397,7 +1397,7 @@ if(!function_exists("is_post_protected_by_s2member"))
1397
  *
1398
  * ———— Extra Detail On Function Parameters ————
1399
  *
1400
- * **Parameter $post_id (int Required).** This should be a WordPress® Post ID, or a Custom Post Type ID.
1401
  *
1402
  * o s2Member will check everything, including your configured URI Restrictions against the ID.
1403
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
@@ -1421,7 +1421,7 @@ if(!function_exists("is_post_protected_by_s2member"))
1421
  * @package s2Member\API_Functions
1422
  * @since 3.5
1423
  *
1424
- * @param int $post_id Required. This should be a WordPress® Post ID, or a Custom Post Type ID.
1425
  * @return bool True if the current User IS permitted, else false if the Post is NOT available to the current User;
1426
  * based on your configuration of s2Member, and based on the current User's Role/Capabilities.
1427
  *
@@ -1462,7 +1462,7 @@ if(!function_exists("is_post_permitted_by_s2member"))
1462
  *
1463
  * ———— Extra Detail On Function Parameters ————
1464
  *
1465
- * **Parameter $page_id (int Required).** This should be a WordPress® Page ID.
1466
  *
1467
  * o s2Member will check everything, including your configured URI Restrictions against the ID.
1468
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
@@ -1493,7 +1493,7 @@ if(!function_exists("is_post_permitted_by_s2member"))
1493
  * @package s2Member\API_Functions
1494
  * @since 3.5
1495
  *
1496
- * @param int $page_id Required. This should be a WordPress® Page ID.
1497
  * @param bool $check_user Optional. Consider the current User? Defaults to false.
1498
  * @return array|bool A non-empty array *(meaning true)*, or false if the Page is not protected *(i.e. available publicly)*.
1499
  * When/if the Page IS protected, the return array will include one of these keys ``["s2member_(level|sp|ccap)_req"]``
@@ -1540,7 +1540,7 @@ if(!function_exists("is_page_protected_by_s2member"))
1540
  *
1541
  * ———— Extra Detail On Function Parameters ————
1542
  *
1543
- * **Parameter $page_id (int Required).** This should be a WordPress® Page ID.
1544
  *
1545
  * o s2Member will check everything, including your configured URI Restrictions against the ID.
1546
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
@@ -1564,7 +1564,7 @@ if(!function_exists("is_page_protected_by_s2member"))
1564
  * @package s2Member\API_Functions
1565
  * @since 3.5
1566
  *
1567
- * @param int $page_id Required. This should be a WordPress® Page ID.
1568
  * @return bool True if the current User IS permitted, else false if the Page is NOT available to the current User;
1569
  * based on your configuration of s2Member, and based on the current User's Role/Capabilities.
1570
  *
@@ -1886,28 +1886,28 @@ if(!function_exists("detach_s2member_query_filters"))
1886
  *
1887
  * **Parameter $config (array Required).** This should be an array with one or more of the following elements.
1888
  *
1889
- * o ``"file_download" => "file.zip"`` Location of the file, relative to the `/s2member-files/` directory; or, relative to the root of your Amazon® S3 Bucket, when applicable.
1890
  * o ``"file_download_key" => false`` Defaults to `false`. If `true`, s2Member will return a URL with an s2Member-generated File Download Key. You don't need to generate the File Download Key yourself, s2Member does it for you. If you set this to `ip-forever`, the File Download Key that s2Member generates will last forever, for a specific IP Address; otherwise, by default, all File Download Keys expire after 24 hours automatically. If you set this to `universal`, s2Member will generate a File Download Key that is good for anyone/everyone forever, with NO restrictions on who/where/when a file is accessed *(e.g. be careful with this one)*.
1891
- * o ``"file_stream" => false`` Defaults to `false`. If `true`, s2Member will return a URL containing a parameter/directive, which forces the File Download to take place over the RTMP protocol. This ONLY works when/if s2Member is configured to run with both Amazon® S3/CloudFront. Please note however, it's better to use the example code provided in the your Dashboard. See: `s2Member -› Download Options -› JW Player® and the RTMP Protocol`. Also note, if ``$get_streamer_array`` is passed, s2Member will automatically force ``"file_stream" => true`` for you.
1892
- * o ``"file_inline" => null`` Defaults to `null`. If `true`, s2Member will serve the file inline, instead of as an actual File Download. If empty, s2Member will look at your Inline File Extensions configuration, and serve the file inline; if, and only if, its extension matches one found in your configuration. By default, s2Member serves all files as attachments *(i.e. downloads)*. Please check your Dashboard regarding Inline File Extensions. Also note, this Shortcode Attribute does NOTHING for files served via Amazon® CloudFront. See the tech-notes listed in the Amazon® CloudFront section of your Dashboard for further details and workarounds.
1893
- * o ``"file_storage" => null`` Defaults to `null`. Can be one of `local|s3|cf`. When specified, s2Member will serve the file from a specific source location. For example, if you've configured Amazon® S3 and/or CloudFront; but, there are a few files that you want to upload locally to the `/s2member-files/` directory; you can force s2Member to serve a file from local storage by setting ``"file_storage" => "local"`` explicitly.
1894
  * o ``"file_remote" => false`` Defaults to `false`. If `true`, s2Member will authenticate access to the File Download via Remote Header Authorization, instead of through your web site. This is similar to `.htaccess` protection routines of yester-year. Please check the Remote Authorization and Podcasting section in your Dashboard for further details about how this works.
1895
  * o ``"file_ssl" => null`` Defaults to `null`. If `true`, s2Member will generate a File Download URL with an SSL protocol *( i.e. the URL will start with `https://` or `rtmpe://` )*. If `null`, s2Member will only generate a File Download URL with an SSL protocol, when/if the Post/Page/URL, is also being viewed over SSL. Otherwise, s2Member will use a non-SSL protocol by default.
1896
- * o ``"file_rewrite" => false`` Defaults to `false`. If `true`, s2Member will generate a File Download URL that takes full advantage of s2Member's Advanced Mod Rewrite functionality. If you're running an Apache web server, or another server that supports `mod_rewrite`, we highly recommend turning this on. s2Member's `mod_rewrite` URLs do NOT contain query string parameters, making them more portable/compatible with other software applications and/or plugins for WordPress®.
1897
- * o ``"file_rewrite_base" => null`` Defaults to `null`. If set to a URL, starting with `http` or another valid protocol, s2Member will generate a File Download URL that takes full advantage of s2Member's Advanced Mod Rewrite functionality, and it will use the rewrite base URL as a prefix. This could be useful on some WordPress® installations that use advanced directory structures. It could also be useful for site owners using virtual directories that point to `/s2member-files/`. Note, if `rewrite_base` is set, s2Member will automatically force ``"rewrite" => true`` for you.
1898
  * o ``"skip_confirmation" => false`` Defaults to `false`. If `true`, s2Member will generate a File Download URL which contains a directive, telling s2Member NOT to introduce any JavaScript confirmation prompts on your site, for this File Download URL. Please note, s2Member will automatically detect links, anywhere in your content, and/or anywhere in your theme files, that contain `s2member_file_download` or `s2member-files`. Whenever a logged-in Member clicks a link that contains `s2member_file_download` or `s2member-files`, the system will politely ask the User to confirm the download using a very intuitive JavaScript confirmation prompt, which contains specific details about your configured download limitations. This way your Members will be aware of how many files they've downloaded in the current period; and they'll be able to make a conscious decision about whether to proceed with a specific download or not.
1899
- * o ``"url_to_storage_source" => false`` Defaults to `false`. If `true`, s2Member will generate a File Download URL which points directly to the storage source. This is only functional with Amazon® S3 and/or CloudFront integrations. If you create a URL that points directly to the storage source *(i.e. points directly to Amazon® S3 or CloudFront)*, s2Member will NOT be able to further authenticate the current User/Member; and, s2Member will NOT be able to count the File Download against the current User's account record, because the URL being generated does not pass back through s2Member at all, it points directly to the storage source. For this reason, if you set ``"url_to_storage_source" => true``, you should also set ``"check_user" => true`` and ``"count_against_user" => true``, telling s2Member to authenticate the current User, and if authenticated, count this File Download URL against the current User's account record in real-time *(i.e. as the URL is being generated)*, while it still has a chance to do so. This is useful when you stream files over the RTMP protocol; where an `http://` URL is not feasible. It also helps in situations where a 3rd-party software application will not work as intended, with s2Member's internal redirection to Amazon® S3/CloudFront files. Important, when ``"check_user" => true`` and/or ``"count_against_user" => true``, this API Function will return `false` in situations where the current User/Member does NOT have access to the file.
1900
  * o ``"count_against_user" => false`` Defaults to `false`. If `true`, it will automatically force ``"check_user" => true`` as well. In other words, s2Member will authenticate the current User, and if authenticated, count this File Download URL against the current User's account record in real-time *(i.e. as the URL is being generated)*. This is off by default. By default, s2Member will simply generate a File Download URL, and upon a User/Member clicking the URL, s2Member will authenticate the User/Member at that time, count the File Download against their account record, and serve the File Download. In other words, under normal circumstances, there is no reason to set ``"check_user" => true`` and/or ``"count_against_user" => true`` when generating the URL itself. However, this is a useful config option when ``"url_to_storage_source" => true``. Please note, when ``"check_user" => true`` and/or ``"count_against_user" => true``, this API Function will return `false` in situations where the current User/Member does NOT have access to the file.
1901
  * o ``"check_user => false`` Defaults to `false`. If `true`, s2Member will authenticate the current User before allowing the File Download URL to be generated. This is off by default. By default, s2Member will simply generate a File Download URL, and upon a User/Member clicking the URL, s2Member will authenticate the User/Member at that time, and serve the File Download to the User/Member. In other words, under normal circumstances, there is no reason to set ``"check_user" => true`` and/or ``"count_against_user" => true`` when generating the URL itself. However, this IS a useful config option when ``"url_to_storage_source" => true``. Please note, when ``"check_user" => true`` and/or ``"count_against_user" => true``, this API Function will return `false` in situations where the current User/Member does NOT have access to the file.
1902
  *
1903
- * **Parameter $get_streamer_array (bool Optional).** Defaults to `false`. If `true`, this API Function will return an array with the following elements: `streamer`, `file`, `url`. For further details, please review this section in your Dashboard: `s2Member -› Download Options -› JW Player® & RTMP Protocol Examples`. Note, if this is true, s2Member will automatically force ``"url_to_storage_source" => true`` and ``"file_stream" => true``. For that reason, you should carefully review the details and warning above regarding `url_to_storage_source`. If you set ``$get_streamer_array``, you should also set ``"check_user" => true`` and ``"count_against_user" => true``.
1904
  *
1905
  * @package s2Member\API_Functions
1906
  * @since 110926
1907
  *
1908
  * @param array $config Required. This is an array of configuration options associated with permissions being checked against the current User/Member; and also the actual URL generated by this routine.
1909
  * Possible ``$config`` array elements: `file_download` *(required)*, `file_download_key`, `file_stream`, `file_inline`, `file_storage`, `file_remote`, `file_ssl`, `file_rewrite`, `file_rewrite_base`, `skip_confirmation`, `url_to_storage_source`, `count_against_user`, `check_user`.
1910
- * @param bool $get_streamer_array Optional. Defaults to `false`. If `true`, this API Function will return an array with the following elements: `streamer`, `file`, `url`. For further details, please review this section in your Dashboard: `s2Member -› Download Options -› JW Player® & RTMP Protocol Examples`. Note, if this is true, s2Member will automatically force ``"url_to_storage_source" => true`` and ``"file_stream" => true``. For that reason, you should carefully review the details and warning above regarding `url_to_storage_source`. If you set ``$get_streamer_array``, you should also set ``"check_user" => true`` and ``"count_against_user" => true``.
1911
  * @return str A File Download URL string on success; or an array on success, with elements `streamer`, `file`, `url` when/if ``$get_streamer_array`` is true; else false on any type of failure.
1912
  *
1913
  * @see s2Member\API_Functions\s2member_file_download_key()
@@ -1990,7 +1990,7 @@ if(!function_exists("s2member_file_download_key"))
1990
  * @since 111026
1991
  *
1992
  * @param str|int $user_id Optional. Defaults to the currently logged-in User's ID.
1993
- * @param str $not_counting_this_particular_file Optional. If you want to exclude a particular file, relative to the `/s2member-files/` directory, or relative to the root of your Amazon® S3 Bucket *(when applicable)*.
1994
  * @return array An array with the following elements... File Downloads allowed for this User: (int)`allowed`, Download Period for this User in days: (int)`allowed_days`, Files downloaded by this User in the current Period: (int)`currently`, log of all Files downloaded in the current Period, with file names/dates: (array)`log`, archive of all Files downloaded in prior Periods, with file names/dates: (array)`archive`.
1995
  *
1996
  * @note Calculations returned by this function do NOT include File Downloads that were accessed with an Advanced File Download Key.
@@ -2041,7 +2041,7 @@ if(!function_exists("s2member_user_downloads"))
2041
  * @package s2Member\API_Functions
2042
  * @since 111026
2043
  *
2044
- * @param str $file Required. Location of the file, relative to the `/s2member-files/` directory, or relative to the root of your Amazon® S3 Bucket *(when applicable)*.
2045
  * @param str|int $user_id Optional. If specified, s2Member will return total downloads by a particular User/Member, instead of collectively *(i.e among all Users/Members)*.
2046
  * @param bool $check_archives_too Optional. Defaults to true. When true, s2Member checks its File Download Archive too, instead of ONLY looking at Files downloaded in the current Period. Period is based on your Basic Download Restrictions setting of allowed days across various Levels of Membership, for each respective User/Member. Or, if ``$user_id`` is specified, based solely on a specific User's `allowed_days`, configured in your Basic Download Restrictions, at the User's current Membership Level.
2047
  * @return int The total for this particular ``$file``, based on configuration of function arguments.
@@ -2093,7 +2093,7 @@ if(!function_exists("s2member_total_downloads_of"))
2093
  * @package s2Member\API_Functions
2094
  * @since 111026
2095
  *
2096
- * @param str $file Required. Location of the file, relative to the `/s2member-files/` directory, or relative to the root of your Amazon® S3 Bucket *(when applicable)*.
2097
  * @param str|int $user_id Optional. If specified, s2Member will return total downloads by a particular User/Member, instead of collectively *(i.e among all Users/Members)*.
2098
  * @param bool $check_archives_too Optional. Defaults to true. When true, s2Member checks its File Download Archive too, instead of ONLY looking at Files downloaded in the current Period. Period is based on your Basic Download Restrictions setting of allowed days across various Levels of Membership, for each respective User/Member. Or, if ``$user_id`` is specified, based solely on a specific User's `allowed_days`, configured in your Basic Download Restrictions, at the User's current Membership Level.
2099
  * @return int The total for this particular ``$file``, based on configuration of function arguments.
@@ -2154,7 +2154,7 @@ if(!function_exists("s2member_total_unique_downloads_of"))
2154
  * @param int $user_id Optional. Defaults to the current User's ID.
2155
  * @return int A {@link http://en.wikipedia.org/wiki/Unix_time Unix Timestamp}.
2156
  * The Last Login Time, is the time at which the Username last logged into the site.
2157
- * If the User has never logged into the site (or s2Member® has never recorded them logging in), this will return `0`.
2158
  *
2159
  * @see s2Member\API_Functions\get_user_field()
2160
  */
@@ -2281,7 +2281,7 @@ if(!function_exists("s2member_paid_registration_time"))
2281
  * <!php
2282
  * $s2member_custom = get_user_field ("s2member_custom"); # Custom String value for the current User.
2283
  * $s2member_subscr_id = get_user_field ("s2member_subscr_id"); # Paid Subscr. ID for the current User.
2284
- * $s2member_subscr_or_wp_id = get_user_field ("s2member_subscr_or_wp_id"); # Paid Subscr. ID, else WordPress® User ID.
2285
  * $s2member_subscr_gateway = get_user_field ("s2member_subscr_gateway"); # Paid Subscr. Gateway Code for the current User.
2286
  * $s2member_registration_ip = get_user_field ("s2member_registration_ip"); # IP the current User had during registration.
2287
  * $s2member_custom_fields = get_user_field ("s2member_custom_fields"); # Associative array of all Custom Registration/Profile Fields.
@@ -2290,7 +2290,7 @@ if(!function_exists("s2member_paid_registration_time"))
2290
  * $s2member_auto_eot_time = get_user_field ("s2member_auto_eot_time"); # Auto EOT-Time for the current User (when applicable).
2291
  * $s2member_last_payment_time = get_user_field ("s2member_last_payment_time"); # Timestamp. Last time an actual payment was received by s2Member.
2292
  * $s2member_paid_registration_times = get_user_field ("s2member_paid_registration_times"); # Timestamps. Associative array of all Paid Registration Times.
2293
- * $s2member_access_role = get_user_field ("s2member_access_role"); # A WordPress® Role ID (i.e. s2member_level[0-9]+, administrator, editor, author, contributor, subscriber).
2294
  * $s2member_access_level = get_user_field ("s2member_access_level"); # An s2Member Membership Access Level number.
2295
  * $s2member_access_label = get_user_field ("s2member_access_label"); # An s2Member Membership Access Label (i.e. Bronze, Gold, Silver, Platinum, or whatever is configured).
2296
  * $s2member_access_ccaps = get_user_field ("s2member_access_ccaps"); # An array of Custom Capabilities the current User has (i.e. music,videos).
@@ -2301,10 +2301,10 @@ if(!function_exists("s2member_paid_registration_time"))
2301
  * ```
2302
  * [s2Get user_field="s2member_custom" /] # Custom String value for the current User.
2303
  * [s2Get user_field="s2member_subscr_id" /] # Paid Subscr. ID for the current User.
2304
- * [s2Get user_field="s2member_subscr_or_wp_id" /] # Paid Subscr. ID, else WordPress® User ID.
2305
  * [s2Get user_field="s2member_subscr_gateway" /] # Paid Subscr. Gateway Code for the current User.
2306
  * [s2Get user_field="s2member_registration_ip" /] # IP Address the current User had during registration.
2307
- * [s2Get user_field="s2member_access_role" /] # A WordPress® Role ID (i.e. s2member_level[0-9]+, administrator, editor, author, contributor, subscriber).
2308
  * [s2Get user_field="s2member_access_level" /] # An s2Member Membership Access Level number.
2309
  * [s2Get user_field="s2member_access_label" /] # An s2Member Membership Access Label (i.e. Bronze, Gold, Silver, Platinum, or whatever is configured).
2310
  * [s2Get user_field="s2member_login_counter" /] # Number of times the User has logged into your site.
@@ -2356,10 +2356,10 @@ if(!function_exists("s2member_paid_registration_time"))
2356
  * !>
2357
  * ```
2358
  *
2359
- * ———— Alternative Using ``get_user_option()`` Native To WordPress® ————
2360
- * Most of the s2Member fields are stored in the `usermeta` table (a WordPress® standard),
2361
  * so they could also be retrieved with {@link http://codex.wordpress.org/Function_Reference/get_user_option get_user_option()} if you prefer,
2362
- * which is already native to WordPress®. That being said, {@link s2Member\API_Functions\get_user_field()} is provided by s2Member as a way to retrieve *almost anything*.
2363
  * ```
2364
  * <!php
2365
  * $s2member_custom = get_user_option ("s2member_custom"); # Custom String value for the current User.
@@ -2469,7 +2469,7 @@ if(!function_exists("get_s2member_custom_fields"))
2469
  }
2470
  }
2471
  /**
2472
- * Can be used to auto-fill the `invoice` for PayPal® Button Codes, with a unique Code~IP combination.
2473
  *
2474
  * ———— PHP Code Sample ————
2475
  * ```
19
  /**
20
  * Conditional to determine if the current User is NOT logged in.
21
  *
22
+ * Counterpart {@link http://codex.wordpress.org/Function_Reference/is_user_logged_in is_user_logged_in()} already exists in the WordPress core.
23
  *
24
  * ———— Code Sample Using Both Functions ————
25
  * ```
59
  /**
60
  * Conditional to determine if a specific User is/has a specific Role.
61
  *
62
+ * Another function {@link http://codex.wordpress.org/Function_Reference/user_can user_can()} already exists in the WordPress core.
63
  *
64
  * ———— Code Sample Using Both Functions ————
65
  * ```
100
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
101
  * o A public Visitor will have NO access to protected content.
102
  *
103
+ * WordPress Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
104
+ * WordPress Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
105
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
106
  *
107
  * @package s2Member\API_Functions
108
  * @since 110524RC
109
  *
110
+ * @param int|str $id A numeric WordPress User ID.
111
+ * @param str $role A WordPress Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
112
  * @return bool True if the specific User is/has the specified Role, else false.
113
  *
114
  * @see s2Member\API_Functions\user_is()
145
  /**
146
  * Conditional to determine if a specific User is/does NOT have a specific Role.
147
  *
148
+ * Another function {@link http://codex.wordpress.org/Function_Reference/user_can user_can()} already exists in the WordPress core.
149
  *
150
  * ———— Code Sample Using Three Functions ————
151
  * ```
185
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
186
  * o A public Visitor will have NO access to protected content.
187
  *
188
+ * WordPress Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
189
+ * WordPress Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
190
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
191
  *
192
  * @package s2Member\API_Functions
193
  * @since 110524RC
194
  *
195
+ * @param int|str $id A numeric WordPress User ID.
196
+ * @param str $role A WordPress Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
197
  * @return bool True if the specific User is/does NOT have the specified Role, else false.
198
  *
199
  * @see s2Member\API_Functions\user_is()
222
  /**
223
  * Conditional to determine if the current User is/has a specific Role.
224
  *
225
+ * Another function {@link http://codex.wordpress.org/Function_Reference/current_user_can current_user_can()} already exists in the WordPress core.
226
  *
227
  * ———— Code Sample Using Both Functions ————
228
  * ```
263
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
264
  * o A public Visitor will have NO access to protected content.
265
  *
266
+ * WordPress Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
267
+ * WordPress Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
268
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
269
  *
270
  * @package s2Member\API_Functions
271
  * @since 3.5
272
  *
273
+ * @param str $role A WordPress Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
274
  * @return bool True if the current User is/has the specified Role, else false.
275
  *
276
  * @see s2Member\API_Functions\user_is()
307
  /**
308
  * Conditional to determine if the current User is/does NOT have a specific Role.
309
  *
310
+ * Another function {@link http://codex.wordpress.org/Function_Reference/current_user_can current_user_can()} already exists in the WordPress core.
311
  *
312
  * ———— Code Sample Using Three Functions ————
313
  * ```
347
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
348
  * o A public Visitor will have NO access to protected content.
349
  *
350
+ * WordPress Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
351
+ * WordPress Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
352
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
353
  *
354
  * @package s2Member\API_Functions
355
  * @since 3.5
356
  *
357
+ * @param str $role A WordPress Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
358
  * @return bool True if the current User is/does NOT have the specified Role, else false.
359
  *
360
  * @see s2Member\API_Functions\user_is()
383
  /**
384
  * Conditional to determine if the current User is/has a specific Role, on a specific Blog within a Multisite Network.
385
  *
386
+ * Another function {@link http://codex.wordpress.org/Function_Reference/current_user_can_for_blog current_user_can_for_blog()} already exists in the WordPress core.
387
  *
388
  * ———— Code Sample Using Three Functions ————
389
  * ```
429
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
430
  * o A public Visitor will have NO access to protected content.
431
  *
432
+ * WordPress Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
433
+ * WordPress Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
434
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
435
  *
436
  * @package s2Member\API_Functions
437
  * @since 3.5
438
  *
439
+ * @param int|str $blog_id A WordPress Blog ID *(must be numeric)*.
440
+ * @param str $role A WordPress Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
441
  * @return bool True if the current User is/has the specified Role, on the specified Blog, else false.
442
  *
443
  * @see s2Member\API_Functions\user_is()
474
  /**
475
  * Conditional to determine if the current User is/does NOT have a specific Role, on a specific Blog within a Multisite Network.
476
  *
477
+ * Another function {@link http://codex.wordpress.org/Function_Reference/current_user_can_for_blog current_user_can_for_blog()} already exists in the WordPress core.
478
  *
479
  * ———— Code Sample Using Three Functions ————
480
  * ```
508
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
509
  * o A public Visitor will have NO access to protected content.
510
  *
511
+ * WordPress Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
512
+ * WordPress Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
513
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
514
  *
515
  * @package s2Member\API_Functions
516
  * @since 3.5
517
  *
518
+ * @param int|str $blog_id A WordPress Blog ID *(must be numeric)*.
519
+ * @param str $role A WordPress Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
520
  * @return bool True if the current User is/does NOT have the specified Role, on the specified Blog, else false.
521
  *
522
  * @see s2Member\API_Functions\user_is()
545
  /**
546
  * Conditional to determine if a specific User does NOT have a specific Capability or Role.
547
  *
548
+ * Another function {@link http://codex.wordpress.org/Function_Reference/user_can user_can()} already exists in the WordPress core.
549
  *
550
  * ———— Code Sample Using Both Functions ————
551
  * ```
577
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
578
  * o A public Visitor will have NO access to protected content.
579
  *
580
+ * WordPress Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
581
+ * WordPress Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
582
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
583
  *
584
  * @package s2Member\API_Functions
585
  * @since 3.5
586
  *
587
+ * @param int|str $id A numeric WordPress User ID.
588
+ * @param str $capability A WordPress Capability ID *( i.e. `access_s2member_level[0-9]+`, `access_s2member_ccap_music` )*.
589
  * @return bool True if the specific User does NOT have the specified Capability or Role, else false.
590
  *
591
  * @see s2Member\API_Functions\user_is()
614
  /**
615
  * Conditional to determine if the current User does NOT have a specific Capability or Role.
616
  *
617
+ * Another function {@link http://codex.wordpress.org/Function_Reference/current_user_can current_user_can()} already exists in the WordPress core.
618
  *
619
  * ———— Code Sample Using Both Functions ————
620
  * ```
646
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
647
  * o A public Visitor will have NO access to protected content.
648
  *
649
+ * WordPress Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
650
+ * WordPress Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
651
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
652
  *
653
  * @package s2Member\API_Functions
654
  * @since 3.5
655
  *
656
+ * @param str $capability A WordPress Capability ID *( i.e. `access_s2member_level[0-9]+`, `access_s2member_ccap_music` )*.
657
  * Or a Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
658
  * @return bool True if the current User does NOT have the specified Capability or Role, else false.
659
  *
683
  /**
684
  * Conditional to determine if the current User does NOT have a specific Capability or Role, on a specific Blog within a Multisite Network.
685
  *
686
+ * Another function {@link http://codex.wordpress.org/Function_Reference/current_user_can_for_blog current_user_can_for_blog()} already exists in the WordPress core.
687
  *
688
  * ———— Code Sample Using Both Functions ————
689
  * ```
715
  * o A Subscriber with Level 0 access, can ONLY access Level 0.
716
  * o A public Visitor will have NO access to protected content.
717
  *
718
+ * WordPress Subscribers are at Membership Level 0. If you're allowing Open Registration, Subscribers will be at Level 0 *(a Free Subscriber)*.
719
+ * WordPress Administrators, Editors, Authors, and Contributors have Level 4 access, with respect to s2Member.
720
  * All of their other {@link http://codex.wordpress.org/Roles_and_Capabilities Roles/Capabilities} are left untouched.
721
  *
722
  * @package s2Member\API_Functions
723
  * @since 3.5
724
  *
725
+ * @param int|str $blog_id A WordPress Blog ID *(must be numeric)*.
726
+ * @param str $capability A WordPress Capability ID *( i.e. `access_s2member_level[0-9]+`, `access_s2member_ccap_music` )*.
727
  * Or a Role ID *( i.e. `s2member_level[0-9]+`, `administrator`, `editor`, `author`, `contributor`, `subscriber` )*.
728
  * @return bool True if the current User does NOT have the specified Capability or Role, else false.
729
  *
758
  *
759
  * **Parameter $what (int|str Optional).**
760
  * Defaults to the current $post ID when called from within {@link http://codex.wordpress.org/The_Loop The Loop}.
761
+ * If passed in, this should be a WordPress Category ID, Tag ID, Post ID, or Page ID. Or a full URL. A URI is also fine.
762
  *
763
  * o If you pass in an ID, s2Member will check everything, including your configured URI Restrictions against the ID.
764
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
823
  * @since 3.5
824
  *
825
  * @param int|str $what Optional. Defaults to the current $post ID when called from within {@link http://codex.wordpress.org/The_Loop The Loop}.
826
+ * If passed in, this should be a WordPress Category ID, Tag ID, Post ID, or Page ID. Or a full URL. A URI is also fine.
827
  * @param str $type Optional. One of `category`, `tag`, `post`, `page`, `singular` or `uri`. Defaults to `singular` *(i.e. a Post or Page)*.
828
  * @param bool $check_user Optional. Consider the current User? Defaults to false.
829
  * @return array|bool A non-empty array *(meaning true)*, or false if the content is not protected *(i.e. available publicly)*.
890
  *
891
  * **Parameter $what (int|str Optional).**
892
  * Defaults to the current $post ID when called from within {@link http://codex.wordpress.org/The_Loop The Loop}.
893
+ * If passed in, this should be a WordPress Category ID, Tag ID, Post ID, or Page ID. Or a full URL. A URI is also fine.
894
  *
895
  * o If you pass in an ID, s2Member will check everything, including your configured URI Restrictions against the ID.
896
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
948
  * @since 3.5
949
  *
950
  * @param int|str $what Optional. Defaults to the current $post ID when called from within {@link http://codex.wordpress.org/The_Loop The Loop}.
951
+ * If passed in, this should be a WordPress Category ID, Tag ID, Post ID, or Page ID. Or a full URL. A URI is also fine.
952
  * @param str $type Optional. One of `category`, `tag`, `post`, `page`, `singular` or `uri`. Defaults to `singular` *(i.e. a Post or Page)*.
953
  * @return bool True if the current User IS permitted, else false if the content is NOT available to the current User;
954
  * based on your configuration of s2Member, and based on the current User's Role/Capabilities.
1007
  *
1008
  * ———— Extra Detail On Function Parameters ————
1009
  *
1010
+ * **Parameter $cat_id (int Required).** This should be a WordPress Category ID.
1011
  *
1012
  * o s2Member will check everything, including your configured URI Restrictions against the ID.
1013
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
1038
  * @package s2Member\API_Functions
1039
  * @since 3.5
1040
  *
1041
+ * @param int $cat_id Required. This should be a WordPress Category ID.
1042
  * @param bool $check_user Optional. Consider the current User? Defaults to false.
1043
  * @return array|bool A non-empty array *(meaning true)*, or false if the Category is not protected *(i.e. available publicly)*.
1044
  * When/if the Category IS protected, the return array will include one of these keys ``["s2member_(level|sp|ccap)_req"]``
1085
  *
1086
  * ———— Extra Detail On Function Parameters ————
1087
  *
1088
+ * **Parameter $cat_id (int Required).** This should be a WordPress Category ID.
1089
  *
1090
  * o s2Member will check everything, including your configured URI Restrictions against the ID.
1091
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
1109
  * @package s2Member\API_Functions
1110
  * @since 3.5
1111
  *
1112
+ * @param int $cat_id Required. This should be a WordPress Category ID.
1113
  * @return bool True if the current User IS permitted, else false if the Category is NOT available to the current User;
1114
  * based on your configuration of s2Member, and based on the current User's Role/Capabilities.
1115
  *
1150
  *
1151
  * ———— Extra Detail On Function Parameters ————
1152
  *
1153
+ * **Parameter $tag_id_slug_or_name (int|str Required).** This should be a WordPress Tag ID, Tag Slug, or Tag Name.
1154
  *
1155
  * o s2Member will check everything, including your configured URI Restrictions against the ID, Slug, or Name.
1156
  * In other words, s2Member is capable of determining a URI based on the ID, or Slug, or Name that you pass in.
1194
  * @package s2Member\API_Functions
1195
  * @since 3.5
1196
  *
1197
+ * @param int|str $tag_id_slug_or_name Required. This should be a WordPress Tag ID, Tag Slug, or Tag Name.
1198
  * @param bool $check_user Optional. Consider the current User? Defaults to false.
1199
  * @return array|bool A non-empty array *(meaning true)*, or false if the Tag is not protected *(i.e. available publicly)*.
1200
  * When/if the Tag IS protected, the return array will include one of these keys ``["s2member_(level|sp|ccap)_req"]``
1241
  *
1242
  * ———— Extra Detail On Function Parameters ————
1243
  *
1244
+ * **Parameter $tag_id_slug_or_name (int|str Required).** This should be a WordPress Tag ID, Tag Slug, or Tag Name.
1245
  *
1246
  * o s2Member will check everything, including your configured URI Restrictions against the ID, or Slug, or Name.
1247
  * In other words, s2Member is capable of determining a URI based on the ID, or Slug, or Name that you pass in.
1278
  * @package s2Member\API_Functions
1279
  * @since 3.5
1280
  *
1281
+ * @param int|str $tag_id_slug_or_name Required. This should be a WordPress Tag ID, Tag Slug, or Tag Name.
1282
  * @return bool True if the current User IS permitted, else false if the Tag is NOT available to the current User;
1283
  * based on your configuration of s2Member, and based on the current User's Role/Capabilities.
1284
  *
1319
  *
1320
  * ———— Extra Detail On Function Parameters ————
1321
  *
1322
+ * **Parameter $post_id (int Required).** This should be a WordPress Post ID, or a Custom Post Type ID.
1323
  *
1324
  * o s2Member will check everything, including your configured URI Restrictions against the ID.
1325
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
1350
  * @package s2Member\API_Functions
1351
  * @since 3.5
1352
  *
1353
+ * @param int $post_id Required. This should be a WordPress Post ID, or a Custom Post Type ID.
1354
  * @param bool $check_user Optional. Consider the current User? Defaults to false.
1355
  * @return array|bool A non-empty array *(meaning true)*, or false if the Post is not protected *(i.e. available publicly)*.
1356
  * When/if the Post IS protected, the return array will include one of these keys ``["s2member_(level|sp|ccap)_req"]``
1397
  *
1398
  * ———— Extra Detail On Function Parameters ————
1399
  *
1400
+ * **Parameter $post_id (int Required).** This should be a WordPress Post ID, or a Custom Post Type ID.
1401
  *
1402
  * o s2Member will check everything, including your configured URI Restrictions against the ID.
1403
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
1421
  * @package s2Member\API_Functions
1422
  * @since 3.5
1423
  *
1424
+ * @param int $post_id Required. This should be a WordPress Post ID, or a Custom Post Type ID.
1425
  * @return bool True if the current User IS permitted, else false if the Post is NOT available to the current User;
1426
  * based on your configuration of s2Member, and based on the current User's Role/Capabilities.
1427
  *
1462
  *
1463
  * ———— Extra Detail On Function Parameters ————
1464
  *
1465
+ * **Parameter $page_id (int Required).** This should be a WordPress Page ID.
1466
  *
1467
  * o s2Member will check everything, including your configured URI Restrictions against the ID.
1468
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
1493
  * @package s2Member\API_Functions
1494
  * @since 3.5
1495
  *
1496
+ * @param int $page_id Required. This should be a WordPress Page ID.
1497
  * @param bool $check_user Optional. Consider the current User? Defaults to false.
1498
  * @return array|bool A non-empty array *(meaning true)*, or false if the Page is not protected *(i.e. available publicly)*.
1499
  * When/if the Page IS protected, the return array will include one of these keys ``["s2member_(level|sp|ccap)_req"]``
1540
  *
1541
  * ———— Extra Detail On Function Parameters ————
1542
  *
1543
+ * **Parameter $page_id (int Required).** This should be a WordPress Page ID.
1544
  *
1545
  * o s2Member will check everything, including your configured URI Restrictions against the ID.
1546
  * In other words, s2Member is capable of determining a URI based on the ID that you pass in.
1564
  * @package s2Member\API_Functions
1565
  * @since 3.5
1566
  *
1567
+ * @param int $page_id Required. This should be a WordPress Page ID.
1568
  * @return bool True if the current User IS permitted, else false if the Page is NOT available to the current User;
1569
  * based on your configuration of s2Member, and based on the current User's Role/Capabilities.
1570
  *
1886
  *
1887
  * **Parameter $config (array Required).** This should be an array with one or more of the following elements.
1888
  *
1889
+ * o ``"file_download" => "file.zip"`` Location of the file, relative to the `/s2member-files/` directory; or, relative to the root of your Amazon S3 Bucket, when applicable.
1890
  * o ``"file_download_key" => false`` Defaults to `false`. If `true`, s2Member will return a URL with an s2Member-generated File Download Key. You don't need to generate the File Download Key yourself, s2Member does it for you. If you set this to `ip-forever`, the File Download Key that s2Member generates will last forever, for a specific IP Address; otherwise, by default, all File Download Keys expire after 24 hours automatically. If you set this to `universal`, s2Member will generate a File Download Key that is good for anyone/everyone forever, with NO restrictions on who/where/when a file is accessed *(e.g. be careful with this one)*.
1891
+ * o ``"file_stream" => false`` Defaults to `false`. If `true`, s2Member will return a URL containing a parameter/directive, which forces the File Download to take place over the RTMP protocol. This ONLY works when/if s2Member is configured to run with both Amazon S3/CloudFront. Please note however, it's better to use the example code provided in the your Dashboard. See: `s2Member -› Download Options -› JW Player and the RTMP Protocol`. Also note, if ``$get_streamer_array`` is passed, s2Member will automatically force ``"file_stream" => true`` for you.
1892
+ * o ``"file_inline" => null`` Defaults to `null`. If `true`, s2Member will serve the file inline, instead of as an actual File Download. If empty, s2Member will look at your Inline File Extensions configuration, and serve the file inline; if, and only if, its extension matches one found in your configuration. By default, s2Member serves all files as attachments *(i.e. downloads)*. Please check your Dashboard regarding Inline File Extensions. Also note, this Shortcode Attribute does NOTHING for files served via Amazon CloudFront. See the tech-notes listed in the Amazon CloudFront section of your Dashboard for further details and workarounds.
1893
+ * o ``"file_storage" => null`` Defaults to `null`. Can be one of `local|s3|cf`. When specified, s2Member will serve the file from a specific source location. For example, if you've configured Amazon S3 and/or CloudFront; but, there are a few files that you want to upload locally to the `/s2member-files/` directory; you can force s2Member to serve a file from local storage by setting ``"file_storage" => "local"`` explicitly.
1894
  * o ``"file_remote" => false`` Defaults to `false`. If `true`, s2Member will authenticate access to the File Download via Remote Header Authorization, instead of through your web site. This is similar to `.htaccess` protection routines of yester-year. Please check the Remote Authorization and Podcasting section in your Dashboard for further details about how this works.
1895
  * o ``"file_ssl" => null`` Defaults to `null`. If `true`, s2Member will generate a File Download URL with an SSL protocol *( i.e. the URL will start with `https://` or `rtmpe://` )*. If `null`, s2Member will only generate a File Download URL with an SSL protocol, when/if the Post/Page/URL, is also being viewed over SSL. Otherwise, s2Member will use a non-SSL protocol by default.
1896
+ * o ``"file_rewrite" => false`` Defaults to `false`. If `true`, s2Member will generate a File Download URL that takes full advantage of s2Member's Advanced Mod Rewrite functionality. If you're running an Apache web server, or another server that supports `mod_rewrite`, we highly recommend turning this on. s2Member's `mod_rewrite` URLs do NOT contain query string parameters, making them more portable/compatible with other software applications and/or plugins for WordPress.
1897
+ * o ``"file_rewrite_base" => null`` Defaults to `null`. If set to a URL, starting with `http` or another valid protocol, s2Member will generate a File Download URL that takes full advantage of s2Member's Advanced Mod Rewrite functionality, and it will use the rewrite base URL as a prefix. This could be useful on some WordPress installations that use advanced directory structures. It could also be useful for site owners using virtual directories that point to `/s2member-files/`. Note, if `rewrite_base` is set, s2Member will automatically force ``"rewrite" => true`` for you.
1898
  * o ``"skip_confirmation" => false`` Defaults to `false`. If `true`, s2Member will generate a File Download URL which contains a directive, telling s2Member NOT to introduce any JavaScript confirmation prompts on your site, for this File Download URL. Please note, s2Member will automatically detect links, anywhere in your content, and/or anywhere in your theme files, that contain `s2member_file_download` or `s2member-files`. Whenever a logged-in Member clicks a link that contains `s2member_file_download` or `s2member-files`, the system will politely ask the User to confirm the download using a very intuitive JavaScript confirmation prompt, which contains specific details about your configured download limitations. This way your Members will be aware of how many files they've downloaded in the current period; and they'll be able to make a conscious decision about whether to proceed with a specific download or not.
1899
+ * o ``"url_to_storage_source" => false`` Defaults to `false`. If `true`, s2Member will generate a File Download URL which points directly to the storage source. This is only functional with Amazon S3 and/or CloudFront integrations. If you create a URL that points directly to the storage source *(i.e. points directly to Amazon S3 or CloudFront)*, s2Member will NOT be able to further authenticate the current User/Member; and, s2Member will NOT be able to count the File Download against the current User's account record, because the URL being generated does not pass back through s2Member at all, it points directly to the storage source. For this reason, if you set ``"url_to_storage_source" => true``, you should also set ``"check_user" => true`` and ``"count_against_user" => true``, telling s2Member to authenticate the current User, and if authenticated, count this File Download URL against the current User's account record in real-time *(i.e. as the URL is being generated)*, while it still has a chance to do so. This is useful when you stream files over the RTMP protocol; where an `http://` URL is not feasible. It also helps in situations where a 3rd-party software application will not work as intended, with s2Member's internal redirection to Amazon S3/CloudFront files. Important, when ``"check_user" => true`` and/or ``"count_against_user" => true``, this API Function will return `false` in situations where the current User/Member does NOT have access to the file.
1900
  * o ``"count_against_user" => false`` Defaults to `false`. If `true`, it will automatically force ``"check_user" => true`` as well. In other words, s2Member will authenticate the current User, and if authenticated, count this File Download URL against the current User's account record in real-time *(i.e. as the URL is being generated)*. This is off by default. By default, s2Member will simply generate a File Download URL, and upon a User/Member clicking the URL, s2Member will authenticate the User/Member at that time, count the File Download against their account record, and serve the File Download. In other words, under normal circumstances, there is no reason to set ``"check_user" => true`` and/or ``"count_against_user" => true`` when generating the URL itself. However, this is a useful config option when ``"url_to_storage_source" => true``. Please note, when ``"check_user" => true`` and/or ``"count_against_user" => true``, this API Function will return `false` in situations where the current User/Member does NOT have access to the file.
1901
  * o ``"check_user => false`` Defaults to `false`. If `true`, s2Member will authenticate the current User before allowing the File Download URL to be generated. This is off by default. By default, s2Member will simply generate a File Download URL, and upon a User/Member clicking the URL, s2Member will authenticate the User/Member at that time, and serve the File Download to the User/Member. In other words, under normal circumstances, there is no reason to set ``"check_user" => true`` and/or ``"count_against_user" => true`` when generating the URL itself. However, this IS a useful config option when ``"url_to_storage_source" => true``. Please note, when ``"check_user" => true`` and/or ``"count_against_user" => true``, this API Function will return `false` in situations where the current User/Member does NOT have access to the file.
1902
  *
1903
+ * **Parameter $get_streamer_array (bool Optional).** Defaults to `false`. If `true`, this API Function will return an array with the following elements: `streamer`, `file`, `url`. For further details, please review this section in your Dashboard: `s2Member -› Download Options -› JW Player & RTMP Protocol Examples`. Note, if this is true, s2Member will automatically force ``"url_to_storage_source" => true`` and ``"file_stream" => true``. For that reason, you should carefully review the details and warning above regarding `url_to_storage_source`. If you set ``$get_streamer_array``, you should also set ``"check_user" => true`` and ``"count_against_user" => true``.
1904
  *
1905
  * @package s2Member\API_Functions
1906
  * @since 110926
1907
  *
1908
  * @param array $config Required. This is an array of configuration options associated with permissions being checked against the current User/Member; and also the actual URL generated by this routine.
1909
  * Possible ``$config`` array elements: `file_download` *(required)*, `file_download_key`, `file_stream`, `file_inline`, `file_storage`, `file_remote`, `file_ssl`, `file_rewrite`, `file_rewrite_base`, `skip_confirmation`, `url_to_storage_source`, `count_against_user`, `check_user`.
1910
+ * @param bool $get_streamer_array Optional. Defaults to `false`. If `true`, this API Function will return an array with the following elements: `streamer`, `file`, `url`. For further details, please review this section in your Dashboard: `s2Member -› Download Options -› JW Player & RTMP Protocol Examples`. Note, if this is true, s2Member will automatically force ``"url_to_storage_source" => true`` and ``"file_stream" => true``. For that reason, you should carefully review the details and warning above regarding `url_to_storage_source`. If you set ``$get_streamer_array``, you should also set ``"check_user" => true`` and ``"count_against_user" => true``.
1911
  * @return str A File Download URL string on success; or an array on success, with elements `streamer`, `file`, `url` when/if ``$get_streamer_array`` is true; else false on any type of failure.
1912
  *
1913
  * @see s2Member\API_Functions\s2member_file_download_key()
1990
  * @since 111026
1991
  *
1992
  * @param str|int $user_id Optional. Defaults to the currently logged-in User's ID.
1993
+ * @param str $not_counting_this_particular_file Optional. If you want to exclude a particular file, relative to the `/s2member-files/` directory, or relative to the root of your Amazon S3 Bucket *(when applicable)*.
1994
  * @return array An array with the following elements... File Downloads allowed for this User: (int)`allowed`, Download Period for this User in days: (int)`allowed_days`, Files downloaded by this User in the current Period: (int)`currently`, log of all Files downloaded in the current Period, with file names/dates: (array)`log`, archive of all Files downloaded in prior Periods, with file names/dates: (array)`archive`.
1995
  *
1996
  * @note Calculations returned by this function do NOT include File Downloads that were accessed with an Advanced File Download Key.
2041
  * @package s2Member\API_Functions
2042
  * @since 111026
2043
  *
2044
+ * @param str $file Required. Location of the file, relative to the `/s2member-files/` directory, or relative to the root of your Amazon S3 Bucket *(when applicable)*.
2045
  * @param str|int $user_id Optional. If specified, s2Member will return total downloads by a particular User/Member, instead of collectively *(i.e among all Users/Members)*.
2046
  * @param bool $check_archives_too Optional. Defaults to true. When true, s2Member checks its File Download Archive too, instead of ONLY looking at Files downloaded in the current Period. Period is based on your Basic Download Restrictions setting of allowed days across various Levels of Membership, for each respective User/Member. Or, if ``$user_id`` is specified, based solely on a specific User's `allowed_days`, configured in your Basic Download Restrictions, at the User's current Membership Level.
2047
  * @return int The total for this particular ``$file``, based on configuration of function arguments.
2093
  * @package s2Member\API_Functions
2094
  * @since 111026
2095
  *
2096
+ * @param str $file Required. Location of the file, relative to the `/s2member-files/` directory, or relative to the root of your Amazon S3 Bucket *(when applicable)*.
2097
  * @param str|int $user_id Optional. If specified, s2Member will return total downloads by a particular User/Member, instead of collectively *(i.e among all Users/Members)*.
2098
  * @param bool $check_archives_too Optional. Defaults to true. When true, s2Member checks its File Download Archive too, instead of ONLY looking at Files downloaded in the current Period. Period is based on your Basic Download Restrictions setting of allowed days across various Levels of Membership, for each respective User/Member. Or, if ``$user_id`` is specified, based solely on a specific User's `allowed_days`, configured in your Basic Download Restrictions, at the User's current Membership Level.
2099
  * @return int The total for this particular ``$file``, based on configuration of function arguments.
2154
  * @param int $user_id Optional. Defaults to the current User's ID.
2155
  * @return int A {@link http://en.wikipedia.org/wiki/Unix_time Unix Timestamp}.
2156
  * The Last Login Time, is the time at which the Username last logged into the site.
2157
+ * If the User has never logged into the site (or s2Member has never recorded them logging in), this will return `0`.
2158
  *
2159
  * @see s2Member\API_Functions\get_user_field()
2160
  */
2281
  * <!php
2282
  * $s2member_custom = get_user_field ("s2member_custom"); # Custom String value for the current User.
2283
  * $s2member_subscr_id = get_user_field ("s2member_subscr_id"); # Paid Subscr. ID for the current User.
2284
+ * $s2member_subscr_or_wp_id = get_user_field ("s2member_subscr_or_wp_id"); # Paid Subscr. ID, else WordPress User ID.
2285
  * $s2member_subscr_gateway = get_user_field ("s2member_subscr_gateway"); # Paid Subscr. Gateway Code for the current User.
2286
  * $s2member_registration_ip = get_user_field ("s2member_registration_ip"); # IP the current User had during registration.
2287
  * $s2member_custom_fields = get_user_field ("s2member_custom_fields"); # Associative array of all Custom Registration/Profile Fields.
2290
  * $s2member_auto_eot_time = get_user_field ("s2member_auto_eot_time"); # Auto EOT-Time for the current User (when applicable).
2291
  * $s2member_last_payment_time = get_user_field ("s2member_last_payment_time"); # Timestamp. Last time an actual payment was received by s2Member.
2292
  * $s2member_paid_registration_times = get_user_field ("s2member_paid_registration_times"); # Timestamps. Associative array of all Paid Registration Times.
2293
+ * $s2member_access_role = get_user_field ("s2member_access_role"); # A WordPress Role ID (i.e. s2member_level[0-9]+, administrator, editor, author, contributor, subscriber).
2294
  * $s2member_access_level = get_user_field ("s2member_access_level"); # An s2Member Membership Access Level number.
2295
  * $s2member_access_label = get_user_field ("s2member_access_label"); # An s2Member Membership Access Label (i.e. Bronze, Gold, Silver, Platinum, or whatever is configured).
2296
  * $s2member_access_ccaps = get_user_field ("s2member_access_ccaps"); # An array of Custom Capabilities the current User has (i.e. music,videos).
2301
  * ```
2302
  * [s2Get user_field="s2member_custom" /] # Custom String value for the current User.
2303
  * [s2Get user_field="s2member_subscr_id" /] # Paid Subscr. ID for the current User.
2304
+ * [s2Get user_field="s2member_subscr_or_wp_id" /] # Paid Subscr. ID, else WordPress User ID.
2305
  * [s2Get user_field="s2member_subscr_gateway" /] # Paid Subscr. Gateway Code for the current User.
2306
  * [s2Get user_field="s2member_registration_ip" /] # IP Address the current User had during registration.
2307
+ * [s2Get user_field="s2member_access_role" /] # A WordPress Role ID (i.e. s2member_level[0-9]+, administrator, editor, author, contributor, subscriber).
2308
  * [s2Get user_field="s2member_access_level" /] # An s2Member Membership Access Level number.
2309
  * [s2Get user_field="s2member_access_label" /] # An s2Member Membership Access Label (i.e. Bronze, Gold, Silver, Platinum, or whatever is configured).
2310
  * [s2Get user_field="s2member_login_counter" /] # Number of times the User has logged into your site.
2356
  * !>
2357
  * ```
2358
  *
2359
+ * ———— Alternative Using ``get_user_option()`` Native To WordPress ————
2360
+ * Most of the s2Member fields are stored in the `usermeta` table (a WordPress standard),
2361
  * so they could also be retrieved with {@link http://codex.wordpress.org/Function_Reference/get_user_option get_user_option()} if you prefer,
2362
+ * which is already native to WordPress. That being said, {@link s2Member\API_Functions\get_user_field()} is provided by s2Member as a way to retrieve *almost anything*.
2363
  * ```
2364
  * <!php
2365
  * $s2member_custom = get_user_option ("s2member_custom"); # Custom String value for the current User.
2469
  }
2470
  }
2471
  /**
2472
+ * Can be used to auto-fill the `invoice` for PayPal Button Codes, with a unique Code~IP combination.
2473
  *
2474
  * ———— PHP Code Sample ————
2475
  * ```
includes/functions/pluggables.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Pluggable functions within WordPress®.
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
1
  <?php
2
  /**
3
+ * Pluggable functions within WordPress.
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
includes/hooks.inc.php CHANGED
@@ -51,6 +51,8 @@ add_action("init", "c_ws_plugin__s2member_labels::config_label_translations", 10
51
 
52
  add_action("init", "c_ws_plugin__s2member_login_redirects_r::remove_login_redirect_filters", 11);
53
 
 
 
54
  add_action("admin_init", "c_ws_plugin__s2member_menu_pages::log_file_downloader");
55
  add_action("admin_init", "c_ws_plugin__s2member_menu_pages::logs_zip_downloader");
56
 
@@ -68,7 +70,11 @@ add_action("wp_print_scripts", "c_ws_plugin__s2member_css_js_themes::add_js_w_gl
68
 
69
  add_action("wp_login_failed", "c_ws_plugin__s2member_brute_force::track_failed_logins");
70
  add_filter("authenticate", "c_ws_plugin__s2member_brute_force::stop_brute_force_logins", 100);
71
- add_filter("wp_authenticate_user", "c_ws_plugin__s2member_login_redirects::ms_wp_authenticate_user", 100);
 
 
 
 
72
 
73
  add_action("delete_user", "c_ws_plugin__s2member_user_deletions::handle_user_deletions");
74
  add_action("wpmu_delete_user", "c_ws_plugin__s2member_user_deletions::handle_ms_user_deletions");
51
 
52
  add_action("init", "c_ws_plugin__s2member_login_redirects_r::remove_login_redirect_filters", 11);
53
 
54
+ add_action("init", "c_ws_plugin__s2member_login_checks::monitor_simultaneous_logins", 10);
55
+
56
  add_action("admin_init", "c_ws_plugin__s2member_menu_pages::log_file_downloader");
57
  add_action("admin_init", "c_ws_plugin__s2member_menu_pages::logs_zip_downloader");
58
 
70
 
71
  add_action("wp_login_failed", "c_ws_plugin__s2member_brute_force::track_failed_logins");
72
  add_filter("authenticate", "c_ws_plugin__s2member_brute_force::stop_brute_force_logins", 100);
73
+
74
+ add_filter("wp_authenticate_user", "c_ws_plugin__s2member_login_checks::ms_wp_authenticate_user", 100);
75
+ add_filter("wp_authenticate_user", "c_ws_plugin__s2member_login_checks::stop_simultaneous_logins", 100);
76
+ add_action("wp_login", "c_ws_plugin__s2member_login_checks::update_simultaneous_logins", 1);
77
+ add_action("clear_auth_cookie", "c_ws_plugin__s2member_login_checks::simultaneous_logout", 1);
78
 
79
  add_action("delete_user", "c_ws_plugin__s2member_user_deletions::handle_user_deletions");
80
  add_action("wpmu_delete_user", "c_ws_plugin__s2member_user_deletions::handle_ms_user_deletions");
includes/jquery/jquery.json-ps/jquery.json-ps.js CHANGED
@@ -12,7 +12,7 @@
12
  * if(!this.JSON){this.JSON={}}(function(){var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}JSON.__stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.__stringify")}return str("",{"":value})};JSON.__parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.__parse")}}());
13
  * Modified to work via: `$.JSON.stringify` and `$.JSON.parse`.
14
  *
15
- * Distributed with WordPress® themes/plugins by WebSharks, Inc.
16
  *
17
  * Copyright: © 2009-2011
18
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
12
  * if(!this.JSON){this.JSON={}}(function(){var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}JSON.__stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.__stringify")}return str("",{"":value})};JSON.__parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.__parse")}}());
13
  * Modified to work via: `$.JSON.stringify` and `$.JSON.parse`.
14
  *
15
+ * Distributed with WordPress themes/plugins by WebSharks, Inc.
16
  *
17
  * Copyright: © 2009-2011
18
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
includes/jquery/jquery.sprintf/jquery.sprintf.js CHANGED
@@ -7,7 +7,7 @@
7
  * Based on: {@link http://phpjs.org/functions/sprintf:522} see: {@link http://phpjs.org/pages/license}
8
  * Modified to work via: `$.sprintf()` using jQuery.
9
  *
10
- * Distributed with WordPress® themes/plugins by WebSharks, Inc.
11
  *
12
  * Copyright: © 2009-2011
13
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
7
  * Based on: {@link http://phpjs.org/functions/sprintf:522} see: {@link http://phpjs.org/pages/license}
8
  * Modified to work via: `$.sprintf()` using jQuery.
9
  *
10
+ * Distributed with WordPress themes/plugins by WebSharks, Inc.
11
  *
12
  * Copyright: © 2009-2011
13
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
includes/jquery/jquery.ui-effects/jquery.ui-effects.js CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * jQuery UI Effects. See {@link http://docs.jquery.com/UI/Effects/}
3
  *
4
- * Distributed with WordPress® themes/plugins by WebSharks, Inc.
5
  *
6
  * Copyright: © 2009-2011
7
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
1
  /**
2
  * jQuery UI Effects. See {@link http://docs.jquery.com/UI/Effects/}
3
  *
4
+ * Distributed with WordPress themes/plugins by WebSharks, Inc.
5
  *
6
  * Copyright: © 2009-2011
7
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
includes/menu-pages/api-ops.inc.php CHANGED
@@ -32,7 +32,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
32
  echo '<div class="wrap ws-menu-page">' . "\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>' . "\n";
35
- echo '<h2>s2Member® API / Notifications</h2>' . "\n";
36
 
37
  echo '<table class="ws-menu-page-table">' . "\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">' . "\n";
@@ -55,7 +55,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
55
  echo '<h3>Signup Notification URLs (optional)</h3>' . "\n";
56
  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 "new", "paying" Member signs up. Depending on your fee structure, this may include a payment that establishes their Subscription, or it may not. This Notification will only be triggered once for each Member. Signup Notifications are sent right after a "new", "paying" Member signs up successfully through your Payment Gateway, regardless of whether any money has actually been transacted. In other words, this Notification is triggered anytime a "new", "paying" Member signs up through your Payment Gateway, even if you provided them with something for free <em>(e.g. even if no money is being transacted)</em>.</p>' . "\n";
57
  echo '<p>This Notification will NOT be processed for Free Subscribers that register without going through your Payment Gateway at all (e.g. they simply register on-site; and there is no checkout whatsoever). This Notification will NOT be processed when an "existing" User/Member pays for a new Subscription <em>(see: Modification Notifications for that scenario)</em>.' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' And, this Notification will NOT be processed on Buy Now transactions for Independent Custom Capabilities <em>(see: Payment Notifications for that scenario)</em>.') . '</p>' . "\n";
58
- echo '<p>Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Signup Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
59
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
60
  do_action ("ws_plugin__s2member_during_api_ops_page_during_left_sections_during_signup_notifications", get_defined_vars ());
61
 
@@ -95,7 +95,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
95
 
96
  if(c_ws_plugin__s2member_utils_conds::pro_is_installed())
97
  {
98
- echo '<strong>Coupon Replacement Codes (applicable only w/ s2Member® Pro Forms):</strong>' . "\n";
99
  echo '<ul>' . "\n";
100
  echo '<li><code>%%full_coupon_code%%</code> = A full Coupon Code — if one is accepted by your configuration of s2Member. This may indicate an Affiliate Coupon Code, which will include your Affiliate Suffix Chars too (e.g. the full Coupon Code).</li>' . "\n";
101
  echo '<li><code>%%coupon_code%%</code> = A Coupon Code — if one is accepted by your configuration of s2Member. This will NOT include any Affiliate Suffix Chars. This indicates the actual Coupon Code accepted by your configuration of s2Member (excluding any Affiliate ID).</li>' . "\n";
@@ -156,8 +156,8 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
156
  echo '<div class="ws-menu-page-section ws-plugin--s2member-registration-notifications-section">' . "\n";
157
  echo '<h3>Registration Notification URLs (optional)</h3>' . "\n";
158
  echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever a "new" Member is created, you\'ll want to read this section. This is marked `Registration`, because the URLs that you list below, will be notified each time a "new" Member registers a Username. This is usually triggered right after a `Signup` Notification; at the point in which a "new" Member successfully completes the Registration form, and they are assigned a Username.</p>' . "\n";
159
- echo '<p>This Notification is ALSO triggered whenever you create a "new" User inside your WordPress® Dashboard.</p>' . "\n";
160
- echo '<p>Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Registration Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
161
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
162
  do_action ("ws_plugin__s2member_during_api_ops_page_during_left_sections_during_registration_notifications", get_defined_vars ());
163
 
@@ -191,7 +191,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
191
  echo '<li><code>%%user_login%%</code> = The Username the Member selected during registration.</li>' . "\n";
192
  echo '<li><code>%%user_pass%%</code> = The Password selected or generated during registration.</li>' . "\n";
193
  echo '<li><code>%%user_ip%%</code> = The User\'s IP Address, detected via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
194
- echo '<li><code>%%user_id%%</code> = A unique WordPress® User ID generated during registration.</li>' . "\n";
195
  echo '</ul>' . "\n";
196
 
197
  echo '<strong>Custom Registration/Profile Fields are also supported in this Notification:</strong>' . "\n";
@@ -259,7 +259,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
259
  echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever payment transactions <em>(including Recurring Payments)</em> take place, 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.</p>' . "\n";
260
  echo '<p>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 <em>(i.e. no Free Trial is being offered)</em>, 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.</p>' . "\n";
261
  echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '<p>Payment Notifications are also triggered whenever a Buy Now purchase for Independent Custom Capabilities takes place.</p>' . "\n" : '';
262
- echo '<p>Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Payment Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
263
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
264
  do_action ("ws_plugin__s2member_during_api_ops_page_during_left_sections_during_payment_notifications", get_defined_vars ());
265
 
@@ -297,12 +297,12 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
297
  echo '<li><code>%%user_email%%</code> = The Email Address associated with their User account. This might be different than what is on file with your Payment Gateway.</li>' . "\n";
298
  echo '<li><code>%%user_login%%</code> = The Username associated with their account. The Customer created this during registration.</li>' . "\n";
299
  echo '<li><code>%%user_ip%%</code> = The Customer\'s original IP Address, during checkout/registration via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
300
- echo '<li><code>%%user_id%%</code> = A unique WordPress® User ID that references this account in the WordPress® database.</li>' . "\n";
301
  echo '</ul>' . "\n";
302
 
303
  if(c_ws_plugin__s2member_utils_conds::pro_is_installed())
304
  {
305
- echo '<strong>Coupon Replacement Codes (applicable only w/ s2Member® Pro Forms):</strong><br />' . "\n";
306
  echo '<em>These are ONLY included with payments that occur during checkout. They will NOT be provided with any future recurring payments.</em>'."\n";
307
  echo '<ul>' . "\n";
308
  echo '<li><code>%%full_coupon_code%%</code> = A full Coupon Code — if one is accepted by your configuration of s2Member. This may indicate an Affiliate Coupon Code, which will include your Affiliate Suffix Chars too (e.g. the full Coupon Code).</li>' . "\n";
@@ -373,10 +373,10 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
373
 
374
  echo '<div class="ws-menu-page-section ws-plugin--s2member-modification-notifications-section">' . "\n";
375
  echo '<h3>Modification Notification URLs (optional)</h3>' . "\n";
376
- echo '<p>If you use affiliate software, or have back-office routines that need to be notified each time a new Subscription is created by an "existing" User/Member, or an "existing" Member modifies their paid Subscription terms, you\'ll want to read this section. This is marked `Modification`, because the URLs that you list below, will be notified each time an "existing" User/Member <em>(even if they are/were a Free Subscriber)</em> signs up for a paid Subscription <em>(i.e. a Modification takes place against an existing account within WordPress®)</em>, or an "existing" Member modifies their paid Subscription terms <em>(again, a Modification takes places against an existing account within WordPress®)</em>. Depending on your fee structure, this may include a payment that establishes their Subscription, or it may not.</p>' . "\n";
377
  echo '<p>Modification Notifications are sent right after a Member signs up and/or modifies billing terms successfully through your Payment Gateway, regardless of whether any money has actually been transacted. In other words, this Notification is triggered, even if you provided them with something for free <em>(e.g. even if no money is being transacted)</em>.</p>' . "\n";
378
  echo '<p>This Notification will NOT be processed for "new" Users/Members <em>(see: Signup Notifications for that scenario)</em>.' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' And, this Notification will NOT be processed for Independent Custom Capability purchases <em>(see: Payment Notifications for that scenario)</em>.') . '</p>' . "\n";
379
- echo '<p>Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Modification Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
380
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
381
  do_action ("ws_plugin__s2member_during_api_ops_page_during_left_sections_during_modification_notifications", get_defined_vars ());
382
 
@@ -417,12 +417,12 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
417
  echo '<li><code>%%user_email%%</code> = The Email Address associated with their User account. This might be different than what is on file with your Payment Gateway.</li>' . "\n";
418
  echo '<li><code>%%user_login%%</code> = The Username associated with their account. The Customer created this during registration.</li>' . "\n";
419
  echo '<li><code>%%user_ip%%</code> = The Customer\'s original IP Address, during checkout/registration via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
420
- echo '<li><code>%%user_id%%</code> = A unique WordPress® User ID that references this account in the WordPress® database.</li>' . "\n";
421
  echo '</ul>' . "\n";
422
 
423
  if(c_ws_plugin__s2member_utils_conds::pro_is_installed())
424
  {
425
- echo '<strong>Coupon Replacement Codes (applicable only w/ s2Member® Pro Forms):</strong>' . "\n";
426
  echo '<ul>' . "\n";
427
  echo '<li><code>%%full_coupon_code%%</code> = A full Coupon Code — if one is accepted by your configuration of s2Member. This may indicate an Affiliate Coupon Code, which will include your Affiliate Suffix Chars too (e.g. the full Coupon Code).</li>' . "\n";
428
  echo '<li><code>%%coupon_code%%</code> = A Coupon Code — if one is accepted by your configuration of s2Member. This will NOT include any Affiliate Suffix Chars. This indicates the actual Coupon Code accepted by your configuration of s2Member (excluding any Affiliate ID).</li>' . "\n";
@@ -491,7 +491,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
491
  echo '<div class="ws-menu-page-section ws-plugin--s2member-cancellation-notifications-section">' . "\n";
492
  echo '<h3>Cancellation Notification URLs (optional)</h3>' . "\n";
493
  echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever Subscriptions are cancelled through your Payment Gateway, you\'ll want to read this section. This is marked `Cancellation`, because the URLs that you list below, will be notified each time a Subscription is cancelled. A Cancellation is triggered when you cancel a Customer\'s Subscription through your Payment Gateway, or when a Customer cancels their own Subscription.</p>' . "\n";
494
- echo '<p>Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Cancellation Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
495
  echo '<p><em><strong>*Understanding Cancellations*</strong> It\'s important to realize that a Cancellation is not an EOT (End Of Term). All that happens during a Cancellation event, is that billing is stopped, and it\'s understood that the Customer is going to lose access, at some point in the future. This does NOT mean, that access will be revoked immediately. A separate EOT event will automatically handle a (demotion or deletion) later, at the appropriate time; which could be several days, or even a year after the Cancellation took place.</em></p>' . "\n";
496
  echo '<p><em><strong>*Some Hairy Details*</strong> There might be times whenever you notice that a Member\'s Subscription has been cancelled through your Payment Gateway... 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 an EOT (End Of Term) is processed, a refund occurs, a chargeback occurs, or when a cancellation occurs - which would later result in a delayed Auto-EOT by s2Member.</em></p>' . "\n";
497
  echo '<p><em>s2Member will not process an EOT (End Of Term) 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";
@@ -526,7 +526,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
526
  echo '<li><code>%%user_email%%</code> = The Email Address associated with their User account. This might be different than what is on file with your Payment Gateway.</li>' . "\n";
527
  echo '<li><code>%%user_login%%</code> = The Username associated with their account. The Customer created this during registration.</li>' . "\n";
528
  echo '<li><code>%%user_ip%%</code> = The Customer\'s original IP Address, during checkout/registration via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
529
- echo '<li><code>%%user_id%%</code> = A unique WordPress® User ID that references this account in the WordPress® database.</li>' . "\n";
530
  echo '</ul>' . "\n";
531
 
532
  echo '<strong>Custom Registration/Profile Fields are also supported in this Notification:</strong>' . "\n";
@@ -593,8 +593,8 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
593
  echo '<h3>EOT/Deletion Notification URLs (optional)</h3>' . "\n";
594
  echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever Subscriptions have ended <em>(and a Member is demoted to a Free Subscriber)</em>, 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.</p>' . "\n";
595
  echo '<p><strong>EOT = End Of Term.</strong> An EOT is triggered <em>immediately</em> when you refund a Customer, when a Customer forces a chargeback to occur, or when a paid Subscription ends naturally <em>(i.e. expires)</em>, and your Payment Gateway sends s2Member an EOT (End Of Term) 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. A Cancellation usually results in a delayed EOT, because a Cancellation does NOT always warrant an immediate action; there could still be time left on their Subscription.</p>' . "\n";
596
- echo '<p>Manual Deletions will trigger this Notification too. If you delete an account manually from within your WordPress® Dashboard, your URLs can be notified automatically through this API Notification, and this scenario can be detected through the Replacement Code <code>%%eot_del_type%%</code>, which is documented below. So the two events are an EOT <em>(of any kind)</em> and/or a Manual Deletion.</p>' . "\n";
597
- echo '<p>Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These EOT/Deletion Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
598
  echo '<p><em><strong>*Some Hairy Details*</strong> There might be times whenever you notice that a Member\'s Subscription has been cancelled through your Payment Gateway... 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 an EOT (End Of Term) is processed, a refund occurs, a chargeback occurs, or when a cancellation occurs - which would later result in a delayed Auto-EOT by s2Member.</em></p>' . "\n";
599
  echo '<p><em>s2Member will not process an EOT (End Of Term) 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";
600
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
@@ -627,7 +627,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
627
  echo '<li><code>%%user_email%%</code> = The Email Address associated with their User account. This might be different than what is on file with your Payment Gateway.</li>' . "\n";
628
  echo '<li><code>%%user_login%%</code> = The Username associated with their account. The Customer created this during registration.</li>' . "\n";
629
  echo '<li><code>%%user_ip%%</code> = The Customer\'s original IP Address, during checkout/registration via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
630
- echo '<li><code>%%user_id%%</code> = A unique WordPress® User ID that references this account in the WordPress® database.</li>' . "\n";
631
  echo '</ul>' . "\n";
632
 
633
  echo '<strong>Custom Registration/Profile Fields are also supported in this Notification:</strong>' . "\n";
@@ -695,7 +695,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
695
  echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever Subscriptions have been refunded or reversed <em>(i.e. charged back to you)</em>, 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 EOT/Deletion Notifications, which are all-inclusive.</p>' . "\n";
696
  echo '<p>This is very similar to the EOT/Deletion Notification described above. However, there is an important distinction. The all-inclusive EOT/Deletion Notification includes cancellations, expirations, failed payments, refunds, chargebacks, and even manual deletions by the Administrator from within the Dashboard. In other words, EOT/Deletion Notifications are processed ANY time a deletion or End Of Term action takes place. This API Notification, that is, Refund/Reversal Notifications, do NOT include all of those scenarios.</p>' . "\n";
697
  echo '<p>So the distinction is that Refund/Reversal Notifications are ONLY sent under two specific circumstances: 1. You log into your Payment Gateway and refund a payment that is associated with a Subscription. 2. The Customer complains to your Payment Gateway and a chargeback occurs, forcing a Reversal. In both of these cases, an EOT/Deletion Notification will be sent <em>(as described in the previous section)</em>, but since EOT/Deletion is a broader Notification, these Refund/Reversal Notifications are here so you can nail down specific back-office operations in these two specific scenarios.</p>' . "\n";
698
- echo '<p>Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Refund/Reversal Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
699
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
700
  do_action ("ws_plugin__s2member_during_api_ops_page_during_left_sections_during_refund_reversal_notifications", get_defined_vars ());
701
 
@@ -729,7 +729,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
729
  echo '<li><code>%%item_number%%</code> = The Item Number (colon separated <em>level:custom_capabilities:fixed term</em>) that the payment was for.</li>' . "\n";
730
  echo '<li><code>%%item_name%%</code> = The Item Name (as provided by the <code>desc=""</code> attribute in your Shortcode, which briefly describes the Item Number).</li>' . "\n";
731
  echo '<li><code>%%user_ip%%</code> = The Customer\'s original IP Address, during checkout/registration via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
732
- echo '<li><code>%%user_id%%</code> = A unique WordPress® User ID that references this account in the WordPress® database.</li>' . "\n";
733
  echo '</ul>' . "\n";
734
 
735
  echo '<strong>Custom Registration/Profile Fields are also supported in this Notification:</strong>' . "\n";
@@ -796,7 +796,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
796
  echo '<h3>Specific Post/Page ~ Sale Notification URLs (optional)</h3>' . "\n";
797
  echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever Specific Post/Page sales 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, on a sale providing access to a Specific Post/Page.</p>' . "\n";
798
  echo '<p>This is one of only two API Notifications that are sent for Specific Post/Page Access <em>(i.e. this one, and another below, for Refunds/Reversals)</em>. All of the other API Notifications are designed for Membership Level Access' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' and Independent Custom Capabilities') . '. None of the other API Notifications will ever be processed for Specific Post/Page Access. If you intend to respond to events related to Specific Post/Page Access, you MUST use one of the two API Notifications specifically geared to Post/Page Access.</p>' . "\n";
799
- echo '<p>Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Sale Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
800
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
801
  do_action ("ws_plugin__s2member_during_api_ops_page_during_left_sections_during_sp_sale_notifications", get_defined_vars ());
802
 
@@ -834,7 +834,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
834
 
835
  if(c_ws_plugin__s2member_utils_conds::pro_is_installed())
836
  {
837
- echo '<strong>Coupon Replacement Codes (applicable only w/ s2Member® Pro Forms):</strong>' . "\n";
838
  echo '<ul>' . "\n";
839
  echo '<li><code>%%full_coupon_code%%</code> = A full Coupon Code — if one is accepted by your configuration of s2Member. This may indicate an Affiliate Coupon Code, which will include your Affiliate Suffix Chars too (e.g. the full Coupon Code).</li>' . "\n";
840
  echo '<li><code>%%coupon_code%%</code> = A Coupon Code — if one is accepted by your configuration of s2Member. This will NOT include any Affiliate Suffix Chars. This indicates the actual Coupon Code accepted by your configuration of s2Member (excluding any Affiliate ID).</li>' . "\n";
@@ -898,7 +898,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_api_ops"))
898
  echo '<h3>Specific Post/Page ~ Refund/Reversal Notification URLs (optional)</h3>' . "\n";
899
  echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever sales have been refunded or reversed <em>(i.e. charged back to you)</em>, 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 Refund or Reversal occurs, on a sale that provided access to a Specific Post/Page.</p>' . "\n";
900
  echo '<p>This is one of only two Notifications that are sent for Specific Post/Page Access <em>(i.e. this one, and another above, for Sales)</em>. All of the other API Notifications are designed for Membership Level Access' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' and Independent Custom Capabilities') . '. None of the other API Notifications will ever be processed for Specific Post/Page Access. If you intend to respond to events related to Specific Post/Page Access, you MUST use one of the two API Notifications specifically geared to Post/Page Access.</p>' . "\n";
901
- echo '<p>Please note, this feature is not to be confused with the PayPal® IPN service. PayPal® IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Refund/Reversal Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
902
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
903
  do_action ("ws_plugin__s2member_during_api_ops_page_during_left_sections_during_sp_refund_reversal_notifications", get_defined_vars ());
904
 
32
  echo '<div class="wrap ws-menu-page">' . "\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>' . "\n";
35
+ echo '<h2>s2Member API / Notifications</h2>' . "\n";
36
 
37
  echo '<table class="ws-menu-page-table">' . "\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">' . "\n";
55
  echo '<h3>Signup Notification URLs (optional)</h3>' . "\n";
56
  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 "new", "paying" Member signs up. Depending on your fee structure, this may include a payment that establishes their Subscription, or it may not. This Notification will only be triggered once for each Member. Signup Notifications are sent right after a "new", "paying" Member signs up successfully through your Payment Gateway, regardless of whether any money has actually been transacted. In other words, this Notification is triggered anytime a "new", "paying" Member signs up through your Payment Gateway, even if you provided them with something for free <em>(e.g. even if no money is being transacted)</em>.</p>' . "\n";
57
  echo '<p>This Notification will NOT be processed for Free Subscribers that register without going through your Payment Gateway at all (e.g. they simply register on-site; and there is no checkout whatsoever). This Notification will NOT be processed when an "existing" User/Member pays for a new Subscription <em>(see: Modification Notifications for that scenario)</em>.' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' And, this Notification will NOT be processed on Buy Now transactions for Independent Custom Capabilities <em>(see: Payment Notifications for that scenario)</em>.') . '</p>' . "\n";
58
+ echo '<p>Please note, this feature is not to be confused with the PayPal IPN service. PayPal IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Signup Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
59
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
60
  do_action ("ws_plugin__s2member_during_api_ops_page_during_left_sections_during_signup_notifications", get_defined_vars ());
61
 
95
 
96
  if(c_ws_plugin__s2member_utils_conds::pro_is_installed())
97
  {
98
+ echo '<strong>Coupon Replacement Codes (applicable only w/ s2Member Pro Forms):</strong>' . "\n";
99
  echo '<ul>' . "\n";
100
  echo '<li><code>%%full_coupon_code%%</code> = A full Coupon Code — if one is accepted by your configuration of s2Member. This may indicate an Affiliate Coupon Code, which will include your Affiliate Suffix Chars too (e.g. the full Coupon Code).</li>' . "\n";
101
  echo '<li><code>%%coupon_code%%</code> = A Coupon Code — if one is accepted by your configuration of s2Member. This will NOT include any Affiliate Suffix Chars. This indicates the actual Coupon Code accepted by your configuration of s2Member (excluding any Affiliate ID).</li>' . "\n";
156
  echo '<div class="ws-menu-page-section ws-plugin--s2member-registration-notifications-section">' . "\n";
157
  echo '<h3>Registration Notification URLs (optional)</h3>' . "\n";
158
  echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever a "new" Member is created, you\'ll want to read this section. This is marked `Registration`, because the URLs that you list below, will be notified each time a "new" Member registers a Username. This is usually triggered right after a `Signup` Notification; at the point in which a "new" Member successfully completes the Registration form, and they are assigned a Username.</p>' . "\n";
159
+ echo '<p>This Notification is ALSO triggered whenever you create a "new" User inside your WordPress Dashboard.</p>' . "\n";
160
+ echo '<p>Please note, this feature is not to be confused with the PayPal IPN service. PayPal IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Registration Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
161
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
162
  do_action ("ws_plugin__s2member_during_api_ops_page_during_left_sections_during_registration_notifications", get_defined_vars ());
163
 
191
  echo '<li><code>%%user_login%%</code> = The Username the Member selected during registration.</li>' . "\n";
192
  echo '<li><code>%%user_pass%%</code> = The Password selected or generated during registration.</li>' . "\n";
193
  echo '<li><code>%%user_ip%%</code> = The User\'s IP Address, detected via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
194
+ echo '<li><code>%%user_id%%</code> = A unique WordPress User ID generated during registration.</li>' . "\n";
195
  echo '</ul>' . "\n";
196
 
197
  echo '<strong>Custom Registration/Profile Fields are also supported in this Notification:</strong>' . "\n";
259
  echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever payment transactions <em>(including Recurring Payments)</em> take place, 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.</p>' . "\n";
260
  echo '<p>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 <em>(i.e. no Free Trial is being offered)</em>, 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.</p>' . "\n";
261
  echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '<p>Payment Notifications are also triggered whenever a Buy Now purchase for Independent Custom Capabilities takes place.</p>' . "\n" : '';
262
+ echo '<p>Please note, this feature is not to be confused with the PayPal IPN service. PayPal IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Payment Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
263
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
264
  do_action ("ws_plugin__s2member_during_api_ops_page_during_left_sections_during_payment_notifications", get_defined_vars ());
265
 
297
  echo '<li><code>%%user_email%%</code> = The Email Address associated with their User account. This might be different than what is on file with your Payment Gateway.</li>' . "\n";
298
  echo '<li><code>%%user_login%%</code> = The Username associated with their account. The Customer created this during registration.</li>' . "\n";
299
  echo '<li><code>%%user_ip%%</code> = The Customer\'s original IP Address, during checkout/registration via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
300
+ echo '<li><code>%%user_id%%</code> = A unique WordPress User ID that references this account in the WordPress database.</li>' . "\n";
301
  echo '</ul>' . "\n";
302
 
303
  if(c_ws_plugin__s2member_utils_conds::pro_is_installed())
304
  {
305
+ echo '<strong>Coupon Replacement Codes (applicable only w/ s2Member Pro Forms):</strong><br />' . "\n";
306
  echo '<em>These are ONLY included with payments that occur during checkout. They will NOT be provided with any future recurring payments.</em>'."\n";
307
  echo '<ul>' . "\n";
308
  echo '<li><code>%%full_coupon_code%%</code> = A full Coupon Code — if one is accepted by your configuration of s2Member. This may indicate an Affiliate Coupon Code, which will include your Affiliate Suffix Chars too (e.g. the full Coupon Code).</li>' . "\n";
373
 
374
  echo '<div class="ws-menu-page-section ws-plugin--s2member-modification-notifications-section">' . "\n";
375
  echo '<h3>Modification Notification URLs (optional)</h3>' . "\n";
376
+ echo '<p>If you use affiliate software, or have back-office routines that need to be notified each time a new Subscription is created by an "existing" User/Member, or an "existing" Member modifies their paid Subscription terms, you\'ll want to read this section. This is marked `Modification`, because the URLs that you list below, will be notified each time an "existing" User/Member <em>(even if they are/were a Free Subscriber)</em> signs up for a paid Subscription <em>(i.e. a Modification takes place against an existing account within WordPress)</em>, or an "existing" Member modifies their paid Subscription terms <em>(again, a Modification takes places against an existing account within WordPress)</em>. Depending on your fee structure, this may include a payment that establishes their Subscription, or it may not.</p>' . "\n";
377
  echo '<p>Modification Notifications are sent right after a Member signs up and/or modifies billing terms successfully through your Payment Gateway, regardless of whether any money has actually been transacted. In other words, this Notification is triggered, even if you provided them with something for free <em>(e.g. even if no money is being transacted)</em>.</p>' . "\n";
378
  echo '<p>This Notification will NOT be processed for "new" Users/Members <em>(see: Signup Notifications for that scenario)</em>.' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' And, this Notification will NOT be processed for Independent Custom Capability purchases <em>(see: Payment Notifications for that scenario)</em>.') . '</p>' . "\n";
379
+ echo '<p>Please note, this feature is not to be confused with the PayPal IPN service. PayPal IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Modification Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
380
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
381
  do_action ("ws_plugin__s2member_during_api_ops_page_during_left_sections_during_modification_notifications", get_defined_vars ());
382
 
417
  echo '<li><code>%%user_email%%</code> = The Email Address associated with their User account. This might be different than what is on file with your Payment Gateway.</li>' . "\n";
418
  echo '<li><code>%%user_login%%</code> = The Username associated with their account. The Customer created this during registration.</li>' . "\n";
419
  echo '<li><code>%%user_ip%%</code> = The Customer\'s original IP Address, during checkout/registration via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
420
+ echo '<li><code>%%user_id%%</code> = A unique WordPress User ID that references this account in the WordPress database.</li>' . "\n";
421
  echo '</ul>' . "\n";
422
 
423
  if(c_ws_plugin__s2member_utils_conds::pro_is_installed())
424
  {
425
+ echo '<strong>Coupon Replacement Codes (applicable only w/ s2Member Pro Forms):</strong>' . "\n";
426
  echo '<ul>' . "\n";
427
  echo '<li><code>%%full_coupon_code%%</code> = A full Coupon Code — if one is accepted by your configuration of s2Member. This may indicate an Affiliate Coupon Code, which will include your Affiliate Suffix Chars too (e.g. the full Coupon Code).</li>' . "\n";
428
  echo '<li><code>%%coupon_code%%</code> = A Coupon Code — if one is accepted by your configuration of s2Member. This will NOT include any Affiliate Suffix Chars. This indicates the actual Coupon Code accepted by your configuration of s2Member (excluding any Affiliate ID).</li>' . "\n";
491
  echo '<div class="ws-menu-page-section ws-plugin--s2member-cancellation-notifications-section">' . "\n";
492
  echo '<h3>Cancellation Notification URLs (optional)</h3>' . "\n";
493
  echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever Subscriptions are cancelled through your Payment Gateway, you\'ll want to read this section. This is marked `Cancellation`, because the URLs that you list below, will be notified each time a Subscription is cancelled. A Cancellation is triggered when you cancel a Customer\'s Subscription through your Payment Gateway, or when a Customer cancels their own Subscription.</p>' . "\n";
494
+ echo '<p>Please note, this feature is not to be confused with the PayPal IPN service. PayPal IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Cancellation Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
495
  echo '<p><em><strong>*Understanding Cancellations*</strong> It\'s important to realize that a Cancellation is not an EOT (End Of Term). All that happens during a Cancellation event, is that billing is stopped, and it\'s understood that the Customer is going to lose access, at some point in the future. This does NOT mean, that access will be revoked immediately. A separate EOT event will automatically handle a (demotion or deletion) later, at the appropriate time; which could be several days, or even a year after the Cancellation took place.</em></p>' . "\n";
496
  echo '<p><em><strong>*Some Hairy Details*</strong> There might be times whenever you notice that a Member\'s Subscription has been cancelled through your Payment Gateway... 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 an EOT (End Of Term) is processed, a refund occurs, a chargeback occurs, or when a cancellation occurs - which would later result in a delayed Auto-EOT by s2Member.</em></p>' . "\n";
497
  echo '<p><em>s2Member will not process an EOT (End Of Term) 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";
526
  echo '<li><code>%%user_email%%</code> = The Email Address associated with their User account. This might be different than what is on file with your Payment Gateway.</li>' . "\n";
527
  echo '<li><code>%%user_login%%</code> = The Username associated with their account. The Customer created this during registration.</li>' . "\n";
528
  echo '<li><code>%%user_ip%%</code> = The Customer\'s original IP Address, during checkout/registration via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
529
+ echo '<li><code>%%user_id%%</code> = A unique WordPress User ID that references this account in the WordPress database.</li>' . "\n";
530
  echo '</ul>' . "\n";
531
 
532
  echo '<strong>Custom Registration/Profile Fields are also supported in this Notification:</strong>' . "\n";
593
  echo '<h3>EOT/Deletion Notification URLs (optional)</h3>' . "\n";
594
  echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever Subscriptions have ended <em>(and a Member is demoted to a Free Subscriber)</em>, 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.</p>' . "\n";
595
  echo '<p><strong>EOT = End Of Term.</strong> An EOT is triggered <em>immediately</em> when you refund a Customer, when a Customer forces a chargeback to occur, or when a paid Subscription ends naturally <em>(i.e. expires)</em>, and your Payment Gateway sends s2Member an EOT (End Of Term) 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. A Cancellation usually results in a delayed EOT, because a Cancellation does NOT always warrant an immediate action; there could still be time left on their Subscription.</p>' . "\n";
596
+ echo '<p>Manual Deletions will trigger this Notification too. If you delete an account manually from within your WordPress Dashboard, your URLs can be notified automatically through this API Notification, and this scenario can be detected through the Replacement Code <code>%%eot_del_type%%</code>, which is documented below. So the two events are an EOT <em>(of any kind)</em> and/or a Manual Deletion.</p>' . "\n";
597
+ echo '<p>Please note, this feature is not to be confused with the PayPal IPN service. PayPal IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These EOT/Deletion Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
598
  echo '<p><em><strong>*Some Hairy Details*</strong> There might be times whenever you notice that a Member\'s Subscription has been cancelled through your Payment Gateway... 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 an EOT (End Of Term) is processed, a refund occurs, a chargeback occurs, or when a cancellation occurs - which would later result in a delayed Auto-EOT by s2Member.</em></p>' . "\n";
599
  echo '<p><em>s2Member will not process an EOT (End Of Term) 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";
600
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
627
  echo '<li><code>%%user_email%%</code> = The Email Address associated with their User account. This might be different than what is on file with your Payment Gateway.</li>' . "\n";
628
  echo '<li><code>%%user_login%%</code> = The Username associated with their account. The Customer created this during registration.</li>' . "\n";
629
  echo '<li><code>%%user_ip%%</code> = The Customer\'s original IP Address, during checkout/registration via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
630
+ echo '<li><code>%%user_id%%</code> = A unique WordPress User ID that references this account in the WordPress database.</li>' . "\n";
631
  echo '</ul>' . "\n";
632
 
633
  echo '<strong>Custom Registration/Profile Fields are also supported in this Notification:</strong>' . "\n";
695
  echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever Subscriptions have been refunded or reversed <em>(i.e. charged back to you)</em>, 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 EOT/Deletion Notifications, which are all-inclusive.</p>' . "\n";
696
  echo '<p>This is very similar to the EOT/Deletion Notification described above. However, there is an important distinction. The all-inclusive EOT/Deletion Notification includes cancellations, expirations, failed payments, refunds, chargebacks, and even manual deletions by the Administrator from within the Dashboard. In other words, EOT/Deletion Notifications are processed ANY time a deletion or End Of Term action takes place. This API Notification, that is, Refund/Reversal Notifications, do NOT include all of those scenarios.</p>' . "\n";
697
  echo '<p>So the distinction is that Refund/Reversal Notifications are ONLY sent under two specific circumstances: 1. You log into your Payment Gateway and refund a payment that is associated with a Subscription. 2. The Customer complains to your Payment Gateway and a chargeback occurs, forcing a Reversal. In both of these cases, an EOT/Deletion Notification will be sent <em>(as described in the previous section)</em>, but since EOT/Deletion is a broader Notification, these Refund/Reversal Notifications are here so you can nail down specific back-office operations in these two specific scenarios.</p>' . "\n";
698
+ echo '<p>Please note, this feature is not to be confused with the PayPal IPN service. PayPal IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Refund/Reversal Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
699
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
700
  do_action ("ws_plugin__s2member_during_api_ops_page_during_left_sections_during_refund_reversal_notifications", get_defined_vars ());
701
 
729
  echo '<li><code>%%item_number%%</code> = The Item Number (colon separated <em>level:custom_capabilities:fixed term</em>) that the payment was for.</li>' . "\n";
730
  echo '<li><code>%%item_name%%</code> = The Item Name (as provided by the <code>desc=""</code> attribute in your Shortcode, which briefly describes the Item Number).</li>' . "\n";
731
  echo '<li><code>%%user_ip%%</code> = The Customer\'s original IP Address, during checkout/registration via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
732
+ echo '<li><code>%%user_id%%</code> = A unique WordPress User ID that references this account in the WordPress database.</li>' . "\n";
733
  echo '</ul>' . "\n";
734
 
735
  echo '<strong>Custom Registration/Profile Fields are also supported in this Notification:</strong>' . "\n";
796
  echo '<h3>Specific Post/Page ~ Sale Notification URLs (optional)</h3>' . "\n";
797
  echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever Specific Post/Page sales 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, on a sale providing access to a Specific Post/Page.</p>' . "\n";
798
  echo '<p>This is one of only two API Notifications that are sent for Specific Post/Page Access <em>(i.e. this one, and another below, for Refunds/Reversals)</em>. All of the other API Notifications are designed for Membership Level Access' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' and Independent Custom Capabilities') . '. None of the other API Notifications will ever be processed for Specific Post/Page Access. If you intend to respond to events related to Specific Post/Page Access, you MUST use one of the two API Notifications specifically geared to Post/Page Access.</p>' . "\n";
799
+ echo '<p>Please note, this feature is not to be confused with the PayPal IPN service. PayPal IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Sale Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
800
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
801
  do_action ("ws_plugin__s2member_during_api_ops_page_during_left_sections_during_sp_sale_notifications", get_defined_vars ());
802
 
834
 
835
  if(c_ws_plugin__s2member_utils_conds::pro_is_installed())
836
  {
837
+ echo '<strong>Coupon Replacement Codes (applicable only w/ s2Member Pro Forms):</strong>' . "\n";
838
  echo '<ul>' . "\n";
839
  echo '<li><code>%%full_coupon_code%%</code> = A full Coupon Code — if one is accepted by your configuration of s2Member. This may indicate an Affiliate Coupon Code, which will include your Affiliate Suffix Chars too (e.g. the full Coupon Code).</li>' . "\n";
840
  echo '<li><code>%%coupon_code%%</code> = A Coupon Code — if one is accepted by your configuration of s2Member. This will NOT include any Affiliate Suffix Chars. This indicates the actual Coupon Code accepted by your configuration of s2Member (excluding any Affiliate ID).</li>' . "\n";
898
  echo '<h3>Specific Post/Page ~ Refund/Reversal Notification URLs (optional)</h3>' . "\n";
899
  echo '<p>If you use affiliate software, or have back-office routines that need to be notified whenever sales have been refunded or reversed <em>(i.e. charged back to you)</em>, 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 Refund or Reversal occurs, on a sale that provided access to a Specific Post/Page.</p>' . "\n";
900
  echo '<p>This is one of only two Notifications that are sent for Specific Post/Page Access <em>(i.e. this one, and another above, for Sales)</em>. All of the other API Notifications are designed for Membership Level Access' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' and Independent Custom Capabilities') . '. None of the other API Notifications will ever be processed for Specific Post/Page Access. If you intend to respond to events related to Specific Post/Page Access, you MUST use one of the two API Notifications specifically geared to Post/Page Access.</p>' . "\n";
901
+ echo '<p>Please note, this feature is not to be confused with the PayPal IPN service. PayPal IPN <em>(and other service integrations)</em> are already built into s2Member. They remain active at all times. These Refund/Reversal Notifications are an added layer of functionality, and they are completely optional.</p>' . "\n";
902
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/building-an-api-notification-handler/" target="_blank" rel="external">Building An API Notification Handler</a>.</p>'."\n";
903
  do_action ("ws_plugin__s2member_during_api_ops_page_during_left_sections_during_sp_refund_reversal_notifications", get_defined_vars ());
904
 
includes/menu-pages/down-ops.inc.php CHANGED
@@ -32,7 +32,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
32
  echo '<div class="wrap ws-menu-page">'."\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>'."\n";
35
- echo '<h2>s2Member® File Download Options</h2>'."\n";
36
 
37
  echo '<table class="ws-menu-page-table">'."\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">'."\n";
@@ -115,7 +115,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
115
 
116
  echo '<div class="ws-menu-page-section ws-plugin--s2member-limit-exceeded-page-section">'."\n";
117
  echo '<h3>Download Limit Exceeded Page (required, if providing access to protected files)</h3>'."\n";
118
- echo '<p>This Page will be shown when/if a Member reaches their download limit, based on your configuration of <strong>Basic Download Restrictions</strong> above. This Page should be created by you, in WordPress®. This Page should provide an informative message to the Member, describing your file access restrictions. Just tell them a little bit about your policy on file downloads, and why they might have reached this Page.</p>'."\n";
119
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_limit_exceeded_page", get_defined_vars());
120
 
121
  echo '<table class="form-table">'."\n";
@@ -235,7 +235,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
235
  echo '<div class="ws-menu-page-section ws-plugin--s2member-remote-authorization-section">'."\n";
236
  echo '<h3>Remote Header Authorization (optional)</h3>'."\n";
237
  echo '<p>This can be enabled on a case-by-case basis. Just add this to the end of your download links: <code>&amp;s2member_file_remote=yes</code>. Shortcode alternative: <code>[s2File download="example-file.zip" remote="yes" /]</code>.</p>'."\n";
238
- echo '<p>Remote Header Authorization allows access to file downloads through an entirely different approach. Instead of asking the Member to log into your site through a browser, a Member will be prompted automatically, to log in through HTTP Header Authorization prompts; which is the same technique used in more traditional security systems via .htaccess files. In other words, Remote Header Authorization makes it possible for your Members to access files through remote applications that may NOT use a browser. This is often the case when a Member needs to access protected files through a software client like iTunes®; typical with podcasts. See <a href="http://www.s2member.com/videos/71F49478D6983A9C/" target="_blank" rel="external">tutorial video here</a> for details about how to setup a Podcast for iTunes®.</p>'."\n";
239
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_remote_authorization", get_defined_vars());
240
  echo '</div>'."\n";
241
 
@@ -248,22 +248,22 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
248
  {
249
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_before_amazon_s3", get_defined_vars());
250
 
251
- echo '<div class="ws-menu-page-group" title="Amazon® S3/CDN Storage Option"'.((c_ws_plugin__s2member_menu_pages::$pre_display_errors["cf_files_auto_configure_distros"]) ? ' default-state="open"' : '').'>'."\n";
252
 
253
  echo '<div class="ws-menu-page-section ws-plugin--s2member-amazon-s3-section">'."\n";
254
- echo '<h3>Amazon® S3/CDN Storage &amp; Delivery (optional)</h3>'."\n";
255
  echo '<a href="http://aws.amazon.com/s3/" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/amazon-logo.png" class="ws-menu-page-right" style="width:250px; height:100px; border:0;" alt="." /></a>'."\n";
256
- echo '<p>Please note, all of this is optional. s2Member can be configured here to ONLY use Amazon® S3 <em>(i.e. without Amazon® CloudFront)</em>. Or, s2Member can be configured to use BOTH Amazon® S3 and Amazon® CloudFront together. If you want to use Amazon® S3 Storage, but you don\'t care about Amazon® CloudFront, feel free to leave the entire Amazon® CloudFront section empty. The configuration options in the Amazon® CloudFront section are ONLY required if you are planning to use both Amazon® S3 and Amazon® CloudFront together.</p>'."\n";
257
- echo '<p>Amazon® Simple Storage Service (<a href="http://aws.amazon.com/s3/" target="_blank" rel="external">Amazon® S3</a>). Amazon® S3 is storage for the Internet. It is designed to make web-scale computing easier for developers. Amazon® S3 provides a simple web services interface that can be used to store and retrieve any amount of data, at any time, from anywhere on the web. It gives developers access to the same highly scalable, reliable, secure, fast, inexpensive infrastructure that Amazon® uses to run its own global network of web sites. s2Member has been integrated with Amazon® S3, so that <em>(if you wish)</em>, instead of using the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory, you can store all of your protected files inside an Amazon® S3 Bucket.</p>'."\n";
258
- echo '<p>If you configure the options below, s2Member will assume all protected files are inside your Amazon® S3 Bucket; and the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory is no longer used at all. That being said, all other aspects of s2Member\'s File Download protection remain the same. The only thing that changes, is the location of your protected files. In other words, Basic Download Restrictions, Download Keys, Inline Extensions, Custom Capability and/or Membership Level Files will all continue to work just as before. The only difference is that s2Member will use your Amazon® S3 Bucket as a CDN <em>(i.e. Content Delivery Network)</em> instead of the local <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory.</p>'."\n";
259
- echo '<p>s2Member assumes that you\'re creating a new Amazon® S3 Bucket, specifically for this installation; and that your Bucket is NOT available publicly. In other words, if you type this URL into your browser <em>(i.e. <code>http://your-bucket-name.s3.amazonaws.com/</code>)</em>, you should get an error that says: <code>Access Denied</code>. That\'s good, that\'s exactly what you want. You can create your Amazon® S3 Bucket using the <a href="https://console.aws.amazon.com/s3/home" target="_blank" rel="external">Amazon® interface</a>. Or, some people prefer to use this popular Firefox® extension (<a href="http://www.s3fox.net/" target="_blank" rel="external">S3 Fox Organizer</a>).</p>'."\n";
260
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_amazon_s3", get_defined_vars());
261
 
262
  echo '<div class="ws-menu-page-hr"></div>'."\n";
263
 
264
- echo '<p><em><strong>Dev Note w/Technical Details:</strong> s2Member uses "Digitally Signed URLs", authenticated by the Amazon® S3 API. Documented for developers <a href="http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?RESTAuthentication.html" target="_blank" rel="external">here</a>. To put it simply, s2Member will generate Amazon® S3 URLs (internally); which allow Customers temporary access to specific files inside your S3 Bucket. s2Member\'s Digitally Signed URLs leading to Amazon® S3, give a Customer 24 hours to connect to the file inside your S3 Bucket. This connection period of 24 hours is largely irrelevant when used in combination with s2Member, because access is renewed for another 24 hours each time you make a file available to a User/Member, and they are authenticated by your configuration of s2Member. This connection period of 24 hours is just a secondary line of defense to further prevent the possibility of link sharing. If you need to change this connection timeout of <code>24 hours</code> for some reason (not likely), you can use this WordPress® Filter: <code>ws_plugin__s2member_amazon_s3_file_expires_time</code>.</em></p>'."\n";
265
- echo '<p><em><strong>Linking To Protected Files:</strong> Nothing changes. s2Member\'s integration with Amazon® S3 serves protected files through the same links that all s2Member site owners use. For example, you might use: <code>'.esc_html(site_url("/?s2member_file_download=example-file.zip")).'</code>, where <strong>s2member_file_download</strong> = the file, relative to the root of your Amazon® S3 Bucket. In other words, just the file name in most cases. s2Member will redirect Users/Members to a digitally signed Amazon® S3 URL, which allows them access to a particular file via Amazon® S3. For further details, please review this section of your Dashboard: <code>s2Member -› Download Options -› Basic Download Restrictions</code>. Also see: <code>s2Member -› Download Options -› Advanced Mod-Rewrite Linkage</code>.</em></p>'."\n";
266
- echo '<p><em><strong>Content Type, Disposition &amp; Inline Files:</strong> The query string parameter <code>&amp;s2member_file_inline=yes</code> DOES work for files served directly through Amazon® S3. s2Member DOES have control over the <code>Content-Type</code> and <code>Content-Disposition</code> headers for files being served through Amazon® S3. However, Amazon® CloudFront servers do NOT automatically determine the MIME type for the objects they serve. If you integrate both Amazon® S3 and CloudFront, s2Member will NOT have control over headers. Therefore, when you upload a file to your Amazon® S3 Bucket, you should set its Content-Type header. Again, with the Amazon® S3/CloudFront combination, you MUST configure headers yourself (such as <code>Content-Type: video/webm</code>, or <code>Content-Disposition: inline|attachment</code>) that you want Amazon® CloudFront to send for a particular file. It\'s quite easy. You do this by setting <code>Properties -› Metadata (i.e. headers)</code> on a per-file basis, from inside your Amazon® S3 Management Console. In short, when you upload a file to your Amazon® S3 Bucket, if you want that file to be served a certain way, be sure to configure its <code>Properties -› Metadata</code> accordingly.</em></p>'."\n";
267
 
268
  echo '<div class="ws-menu-page-hr"></div>'."\n";
269
 
@@ -273,7 +273,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
273
 
274
  echo '<th style="padding-top:0;">'."\n";
275
  echo '<label for="ws-plugin--s2member-amazon-s3-files-bucket">'."\n";
276
- echo 'Amazon® S3 File Bucket Name (where protected files are):'."\n";
277
  echo '</label>'."\n";
278
  echo '</th>'."\n";
279
 
@@ -282,7 +282,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
282
 
283
  echo '<td>'."\n";
284
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_amazon_s3_files_bucket" id="ws-plugin--s2member-amazon-s3-files-bucket" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"]).'" /><br />'."\n";
285
- echo 'Your Amazon® S3 Bucket will be used, instead of the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory.<br />'."\n";
286
  echo 'Please type the name of your Bucket. Ex: <code>mys3bucket</code>'."\n";
287
  echo '</td>'."\n";
288
 
@@ -291,7 +291,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
291
 
292
  echo '<th>'."\n";
293
  echo '<label for="ws-plugin--s2member-amazon-s3-files-access-key">'."\n";
294
- echo 'Amazon® Access Key (Access Key ID):'."\n";
295
  echo '</label>'."\n";
296
  echo '</th>'."\n";
297
 
@@ -300,7 +300,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
300
 
301
  echo '<td>'."\n";
302
  echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_amazon_s3_files_access_key" id="ws-plugin--s2member-amazon-s3-files-access-key" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_access_key"]).'" /><br />'."\n";
303
- echo 'See: <code>Amazon® Web Services Account -› Security Credentials -› Access Keys</code>.'."\n";
304
  echo '</td>'."\n";
305
 
306
  echo '</tr>'."\n";
@@ -308,7 +308,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
308
 
309
  echo '<th>'."\n";
310
  echo '<label for="ws-plugin--s2member-amazon-s3-files-secret-key">'."\n";
311
- echo 'Amazon® Secret Key (Secret Access Key):'."\n";
312
  echo '</label>'."\n";
313
  echo '</th>'."\n";
314
 
@@ -317,8 +317,8 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
317
 
318
  echo '<td>'."\n";
319
  echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_amazon_s3_files_secret_key" id="ws-plugin--s2member-amazon-s3-files-secret-key" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"]).'" /><br />'."\n";
320
- echo 'See: <code>Amazon® Web Services Account -› Security Credentials -› Access Keys (leading to: Legacy Security Credentials)</code>.<br />'."\n";
321
- echo 'Amazon® is deprecating Secret Access Keys, but they ARE still required for digitally signed URLs.'."\n";
322
  echo '</td>'."\n";
323
 
324
  echo '</tr>'."\n";
@@ -335,31 +335,31 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
335
  {
336
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_before_amazon_cf", get_defined_vars());
337
 
338
- echo '<div class="ws-menu-page-group" title="Amazon® S3/CloudFront CDN Storage Option"'.((c_ws_plugin__s2member_menu_pages::$pre_display_errors["cf_files_auto_configure_distros"]) ? ' default-state="open"' : '').'>'."\n";
339
 
340
  echo '<div class="ws-menu-page-section ws-plugin--s2member-amazon-cf-section">'."\n";
341
- echo '<h3>Amazon® S3/CloudFront CDN Storage &amp; Delivery (optional)</h3>'."\n";
342
  echo '<a href="http://aws.amazon.com/cloudfront/" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/amazon-logo.png" class="ws-menu-page-right" style="width:250px; height:100px; border:0;" alt="." /></a>'."\n";
343
- echo '<p>Please note, all of this is optional. s2Member can be configured to ONLY use Amazon® S3 <em>(i.e. without Amazon® CloudFront)</em>. Or, s2Member can be configured to use BOTH Amazon® S3 and Amazon® CloudFront together. If you don\'t want to use Amazon® CloudFront, please leave this entire section empty. The configuration options in this section are ONLY required if you are planning to use both Amazon® S3 and Amazon® CloudFront together.</p>'."\n";
344
- echo '<p>Amazon® Simple Storage Service (<a href="http://aws.amazon.com/s3/" target="_blank" rel="external">Amazon® S3</a>) combined with <a href="http://aws.amazon.com/cloudfront/" target="_blank" rel="external">Amazon® CloudFront</a>. Amazon® CloudFront is a web service for content delivery. It integrates with other Amazon® Web Services <em>(i.e. Amazon® S3 Storage)</em> to give developers and businesses an easy way to distribute content to end users with low latency, and with high data transfer speeds. Amazon® CloudFront delivers your static and streaming content using a global network of edge locations. Requests for your Amazon® S3 Bucket Objects <em>(i.e. your protected files)</em> are automatically routed to the nearest edge location, so content is delivered with the best possible performance. s2Member has been integrated with both Amazon® S3 and with Amazon® CloudFront. So <em>(if you wish)</em>, instead of using the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory, you can store all of your protected files inside an Amazon® S3 Bucket and serve them via Amazon® CloudFront. But again, please understand, the configuration options in this section are ONLY required if you\'re going to use both Amazon® S3 &amp; CloudFront together.</p>'."\n";
345
- echo '<p><strong>One of the great things about Amazon® CloudFront</strong>, is its ability to <strong>stream/seek media files</strong> in the truest sense of the word. For sites delivering protected <em>FLV/MP4/OGG/WEBM</em> and other streaming audio/video file types over the <em>RTMP</em> protocol, Amazon® CloudFront is our recommendation. Once you\'ve successfully configured s2Member to use both Amazon® S3 and Amazon® CloudFront together, please review the section below regarding <code>JW Player® &amp; RTMP Protocol Examples</code>. s2Member will automatically serve your protected files over the <em>RTMP</em> protocol using an Amazon® CloudFront Streaming Distribution.</p>'."\n";
346
- echo '<p>If you configure the options below, s2Member will assume all protected files are inside your Amazon® S3 Bucket; and the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory is no longer used at all. That being said, all other aspects of s2Member\'s File Download protection remain the same. The only thing that changes, is the location of your protected files. In other words, Basic Download Restrictions, Download Keys, Custom Capability and/or Membership Level Files will all continue to work just as before. The only difference is that s2Member will use your Amazon® S3 Bucket, automatically connecting it to both of the Amazon® CloudFront Distributions, which s2Member auto-configures for you <em>(see below)</em>. In this way, s2Member uses Amazon® CloudFront as a CDN <em>(i.e. Content Delivery Network)</em> for your protected files.</p>'."\n";
347
- echo '<p>s2Member assumes that you\'re creating a new Amazon® S3 Bucket, specifically for this installation; and that your Bucket is NOT available publicly. In other words, if you type this URL into your browser <em>(i.e. <code>http://your-bucket-name.s3.amazonaws.com/</code>)</em>, you should get an error that says: <code>Access Denied</code>. That\'s good, that\'s exactly what you want. You can create your Amazon® S3 Bucket using the <a href="https://console.aws.amazon.com/s3/home" target="_blank" rel="external">Amazon® interface</a>. Or, some people prefer to use this popular Firefox® extension (<a href="http://www.s3fox.net/" target="_blank" rel="external">S3 Fox Organizer</a>). You will also need to enable CloudFront inside your Web Services account at Amazon®. Don\'t worry about creating or configuring any CloudFront Distributions, s2Member will auto-create and auto-configure those for you, allowing you to serve protected files.</p>'."\n";
348
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_amazon_cf", get_defined_vars());
349
 
350
  echo '<div class="ws-menu-page-hr"></div>'."\n";
351
 
352
- echo '<p><em><strong>Dev Note w/Technical Details:</strong> s2Member\'s auto-configuration routines for Amazon® CloudFront (below), are designed to create &amp; configure various components on your Amazon® Web Services account, which are all requirements for you to <a href="http://docs.amazonwebservices.com/AmazonCloudFront/2010-11-01/DeveloperGuide/index.html?HowToPrivateContent.html" target="_blank" rel="external">serve protected files through the Amazon® S3/CloudFront combination</a>. These components include: an Origin Access Identity, read permissions for the Origin Access Identity, and two private content Distributions. One private content Distribution for file downloads, and another private content Distribution for streaming media files; both connected to and sourced by your Amazon® S3 Bucket. In addition, s2Member will automatically configure an ACL &amp; Policy (i.e. permissions) on your Amazon® S3 Bucket to make sure your protected object/files are NOT available to the public.</em></p>'."\n";
353
- echo '<p><em><strong>Dev Note w/Technical Details:</strong> s2Member uses "Digitally Signed URLs", authenticated by the Amazon® CloudFront API. Documented for developers <a href="http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PrivateContent.html" target="_blank" rel="external">here</a>. To put it simply, s2Member will generate Amazon® CloudFront URLs (internally); which allow Customers temporary access to specific files inside your S3 Bucket — via CloudFront Distributions. s2Member\'s Digitally Signed URLs leading to Amazon® S3/CloudFront, give a Customer 24 hours to connect to the file inside your S3 Bucket. This connection period of 24 hours is largely irrelevant when used in combination with s2Member, because access is renewed for another 24 hours each time you make a file available to a User/Member, and they are authenticated by your configuration of s2Member. This connection period of 24 hours is just a secondary line of defense to further prevent the possibility of link sharing. If you need to change this connection timeout of <code>24 hours</code> for some reason (not likely), you can use this WordPress® Filter: <code>ws_plugin__s2member_amazon_cf_file_expires_time</code>.</em></p>'."\n";
354
- echo '<p><em><strong>Linking To Protected Files:</strong> RTMP streams are special, but nothing else changes. s2Member\'s integration with Amazon® S3/CloudFront serves protected files through the same links that all s2Member site owners use. For example, you might use: <code>'.esc_html(site_url("/?s2member_file_download=example-file.zip")).'</code>, where <strong>s2member_file_download</strong> = the file, relative to the root of your Amazon® S3 Bucket. In other words, just the file name in most cases. s2Member will redirect Users/Members to a digitally signed Amazon® CloudFront URL, which allows them access to a particular file via Amazon® CloudFront. For further details, please review this section of your Dashboard: <code>s2Member -› Download Options -› Basic Download Restrictions</code>. Also see: <code>s2Member -› Download Options -› Advanced Mod-Rewrite Linkage</code>. If you\'re streaming audio/video files over the RTMP protocol, please review the section below: <code>JW Player® &amp; RTMP Protocol Examples</code>.</em></p>'."\n";
355
- echo '<p><em><strong>Content Type, Disposition &amp; Inline Files:</strong> An IMPORTANT issue. The query string parameter <code>&amp;s2member_file_inline=yes</code> does NOTHING for files served via Amazon® CloudFront. s2Member has NO control over the <code>Content-Type</code> and/or <code>Content-Disposition</code> headers for a file being served through Amazon® CloudFront, and CloudFront servers do NOT automatically determine the MIME type for the objects they serve. Therefore, when you upload a file to your Amazon® S3 Bucket, you should set its Content-Type header. That is, you MUST configure headers yourself (such as <code>Content-Type: video/webm</code>, or <code>Content-Disposition: inline|attachment</code>) that you want Amazon® CloudFront to send for a particular file. It\'s quite easy. You do this by setting <code>Properties -› Metadata (i.e. headers)</code> on a per-file basis, from inside your Amazon® S3 Management Console. In short, when you upload a file to your Amazon® S3 Bucket, if you want that file to be served a certain way, be sure to configure its <code>Properties -› Metadata</code> accordingly.</em></p>'."\n";
356
- echo (stripos(PHP_OS, "win") === 0 && c_ws_plugin__s2member_utils_conds::is_localhost()) ? '<p><em><strong>Localhost Developers:</strong> s2Member\'s Amazon® CloudFront integration requires the <a href="http://php.net/manual/en/function.openssl-sign.php" target="_blank" rel="external">openssl_sign()</a> function in PHP so it can digitially sign CloudFront® URLs. This function is sometimes problematic on localhost servers such as WAMP &amp; EasyPHP. We recommend installing <a href="http://www.slproweb.com/products/Win32OpenSSL.html" target="_blank" rel="external">this lightweight alternative for Windows®</a> while you\'re developing. s2Member will automatically find it here: <code>C:\OpenSSL-Win[32/64]\bin\openssl.exe</code>.'.((file_exists("c:\openssl-win32\bin\openssl.exe") || file_exists("c:\openssl-win64\bin\openssl.exe")) ? ' <strong class="ws-menu-page-hilite">( s2Member has detected that OpenSSL-Win[32/64] IS installed in the correct location, thank you! )</strong>' : ' <strong class="ws-menu-page-hilite">(s2Member has detected that OpenSSL-Win[32/64] is NOT currently available)</strong>').'</em></p>'."\n" : '';
357
 
358
  if($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distros_auto_config_status"] === "configured")
359
- echo '<p><em class="ws-menu-page-hilite"><strong>Your Amazon® CloudFront Distributions are: ( ALREADY configured! )</strong></em>'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_downloads_cname"]) ? '<br /><em class="ws-menu-page-hilite">Downloads Distribution CNAME:</em> <em><code>'.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_downloads_cname"]).' &mdash;&raquo; '.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_downloads_dname"]).'</code></em>' : '').(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_streaming_cname"]) ? '<br /><em class="ws-menu-page-hilite">Streaming Distribution CNAME:</em> <em><code>'.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_streaming_cname"]).' &mdash;&raquo; '.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_streaming_dname"]).'</code></em>' : '').'</p>'."\n";
360
 
361
  else if(!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distros_auto_config_status"])
362
- echo '<p><em class="ws-menu-page-hilite"><strong>Your Amazon® CloudFront Distributions are: (NOT yet auto-configured).</strong></em></p>'."\n";
363
 
364
  echo '<div class="ws-menu-page-hr"></div>'."\n";
365
 
@@ -369,7 +369,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
369
 
370
  echo '<th style="padding-top:0;">'."\n";
371
  echo '<label for="ws-plugin--s2member-amazon-cf-files-private-key-id">'."\n";
372
- echo 'Amazon® CloudFront Key Pair ID (your Key Pair ID):'."\n";
373
  echo '</label>'."\n";
374
  echo '</th>'."\n";
375
 
@@ -378,7 +378,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
378
 
379
  echo '<td>'."\n";
380
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_amazon_cf_files_private_key_id" id="ws-plugin--s2member-amazon-cf-files-private-key-id" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_private_key_id"]).'" data-s-prev-config-value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_private_key_id"]).'" /><br />'."\n";
381
- echo 'See: <code>Amazon® Web Services Account -› Security Credentials -› Key Pairs</code>.'."\n";
382
  echo '</td>'."\n";
383
 
384
  echo '</tr>'."\n";
@@ -386,7 +386,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
386
 
387
  echo '<th>'."\n";
388
  echo '<label for="ws-plugin--s2member-amazon-cf-files-private-key-entry">'."\n";
389
- echo 'Amazon® CloudFront Private Key (contents of your <code>pk-[***].pem</code> file):'."\n";
390
  echo '</label>'."\n";
391
  echo '</th>'."\n";
392
 
@@ -396,7 +396,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
396
  echo '<td>'."\n";
397
  echo '<input type="hidden" name="ws_plugin__s2member_amazon_cf_files_private_key" id="ws-plugin--s2member-amazon-cf-files-private-key" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_private_key"]).'" data-s-prev-config-value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_private_key"]).'" />'."\n";
398
  echo '<textarea name="ws_plugin__s2member_amazon_cf_files_private_key_entry" id="ws-plugin--s2member-amazon-cf-files-private-key-entry" rows="3" wrap="off" spellcheck="false" style="font-family:Consolas, monospace;">'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_private_key"]).'</textarea><br />'."\n";
399
- echo 'See: <code>Amazon® Web Services Account -› Security Credentials -› Key Pairs</code>.<br />'."\n";
400
  echo '<em>* Note, s2Member needs your <strong>Private Key file</strong>, NOT your Public Key file.</em>'."\n";
401
  echo '</td>'."\n";
402
 
@@ -405,7 +405,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
405
 
406
  echo '<th>'."\n";
407
  echo '<label for="ws-plugin--s2member-amazon-cf-files-auto-configure-distros">'."\n";
408
- echo 'Auto-Configure your Amazon® S3/CloudFront combination?'."\n";
409
  echo '</label>'."\n";
410
  echo '</th>'."\n";
411
 
@@ -413,8 +413,8 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
413
  echo '<tr>'."\n";
414
 
415
  echo '<td>'."\n";
416
- echo '<input type="checkbox" name="ws_plugin__s2member_amazon_cf_files_auto_configure_distros" id="ws-plugin--s2member-amazon-cf-files-auto-configure-distros" value="'.esc_attr(wp_create_nonce("ws-plugin--s2member-amazon-cf-files-auto-configure-distros")).'"'.((c_ws_plugin__s2member_menu_pages::$pre_display_errors["cf_files_auto_configure_distros"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-amazon-cf-files-auto-configure-distros"><strong>Yes</strong>, automatically configure my Amazon® CloudFront Distributions &amp; Amazon® S3 ACLs for me.</label><br />'."\n";
417
- echo '<em>s2Member will auto-configure and/or delete &amp; re-configure your Amazon® CloudFront Distributions for you.</em>'."\n";
418
  echo '</td>'."\n";
419
 
420
  echo '</tr>'."\n";
@@ -436,7 +436,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
436
 
437
  echo '<th>'."\n";
438
  echo '<label for="ws-plugin--s2member-amazon-cf-files-downloads-distro-cname">'."\n";
439
- echo 'Amazon® CloudFront CNAME for File Downloads (optional):'."\n";
440
  echo '</label>'."\n";
441
  echo '</th>'."\n";
442
 
@@ -454,7 +454,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
454
 
455
  echo '<th>'."\n";
456
  echo '<label for="ws-plugin--s2member-amazon-cf-files-streaming-distro-cname">'."\n";
457
- echo 'Amazon® CloudFront CNAME for Streaming Files (optional):'."\n";
458
  echo '</label>'."\n";
459
  echo '</th>'."\n";
460
 
@@ -482,57 +482,59 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
482
  {
483
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_before_rtmp_streaming", get_defined_vars());
484
 
485
- echo '<div class="ws-menu-page-group" title="JW Player® v6 &amp; RTMP Protocol Examples">'."\n";
486
 
487
  echo '<div class="ws-menu-page-section ws-plugin--s2member-rtmp-streaming-section">'."\n";
488
- echo '<h3>JW Player® v6 &amp; RTMP Protocol Examples</h3>'."\n";
489
  echo '<a href="http://www.longtailvideo.com/players/" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/jwplayer-logo.png" class="ws-menu-page-right" style="width:179px; height:58px; border:0;" alt="." /></a>'."\n";
490
- echo '<p>While it is possible to serve audio/video files protected by s2Member, without needing to integrate Amazon® S3 or CloudFront; we DO highly recommend that you integrate both Amazon® S3 and Amazon® CloudFront in order to maximize speed and compatibility across various viewing platforms. That being said, there are code samples below that will serve audio/video files both with and without Amazon® S3/CloudFront. You can also check the <a href="'.esc_attr(c_ws_plugin__s2member_readmes::parse_readme_value("Forum URI")).'" target="_blank" rel="external">s2Member Support Forums</a> for tips/tricks if you like.</p>'."\n";
491
- echo '<p><strong>One of the great things about Amazon® CloudFront</strong>, is its ability to <strong>stream/seek media files</strong> in the truest sense of the word. For sites delivering protected <em>FLV/MP4/OGG/WEBM</em> and other streaming audio/video file types over the <em>RTMP</em> protocol, Amazon® CloudFront is our recommendation. Once you\'ve successfully configured s2Member to use both Amazon® S3 and Amazon® CloudFront together, please review the code samples below. s2Member can automatically serve your protected files over the <em>RTMP</em> protocol using an Amazon® CloudFront Streaming Distribution.</p>'."\n";
492
- echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/jwplayer-s2stream-shortcodes/" target="_blank" rel="external">JW Player® w/ <code>[s2Stream /]</code> Shortcodes</a>.</p>'."\n";
 
 
493
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_rtmp_streaming", get_defined_vars());
494
 
495
  echo '<div class="ws-menu-page-hr"></div>'."\n";
496
 
497
  echo '<h3><code>[s2Stream /]</code> Video Shortcode Examples (recommended — it\'s the easiest way)</h3>'."\n";
498
 
499
- echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp4\').toggle(); return false;" class="ws-dotted-link">JW Player® (MP4 file, via Rewrite URLs. Amazon® S3/CloudFront NOT required)</a></p>'."\n";
500
- echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp4" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player® here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />Works with any audio/video file. This does NOT require s2Member to be integrated with Amazon® S3/CloudFront.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-s2stream-mp4.x-php")).'</p>'."\n";
501
 
502
- echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp4-rtmp\').toggle(); return false;" class="ws-dotted-link">JW Player® (RTMP streaming MP4, via s2Member\'s Amazon® S3/CloudFront integration)</a></p>'."\n";
503
- echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp4-rtmp" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player® here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />Streams with the RTMP protocol, plus there is a full download fallback of the MP4 source file if streaming is not possible on a particular device.<br />This requires s2Member to be integrated with Amazon® S3/CloudFront.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-s2stream-mp4-rtmp.x-php")).'</p>'."\n";
504
 
505
- echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp4-rtmp-only\').toggle(); return false;" class="ws-dotted-link">JW Player® (RTMP streaming MP4 only, via s2Member\'s Amazon® S3/CloudFront integration)</a></p>'."\n";
506
- echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp4-rtmp-only" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player® here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />Streams with the RTMP protocol only, with no access to the source file, only to the RTMP stream.<br />This requires s2Member to be integrated with Amazon® S3/CloudFront.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-s2stream-mp4-rtmp-only.x-php")).'</p>'."\n";
507
 
508
  echo '<div class="ws-menu-page-hr"></div>'."\n";
509
 
510
  echo '<h3><code>[s2Stream /]</code> Audio Shortcode Examples (recommended — it\'s the easiest way)</h3>'."\n";
511
 
512
- echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp3\').toggle(); return false;" class="ws-dotted-link">JW Player® (MP3 file, via Rewrite URLs. Amazon® S3/CloudFront NOT required)</a></p>'."\n";
513
- echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp3" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player® here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />Works with any audio/video file. This does NOT require s2Member to be integrated with Amazon® S3/CloudFront.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-s2stream-mp3.x-php")).'</p>'."\n";
514
 
515
- echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp3-rtmp\').toggle(); return false;" class="ws-dotted-link">JW Player® (RTMP streaming MP3, via s2Member\'s Amazon® S3/CloudFront integration)</a></p>'."\n";
516
- echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp3-rtmp" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player® here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />Streams with the RTMP protocol, plus there is a full download fallback of the MP3 source file if streaming is not possible on a particular device.<br />This requires s2Member to be integrated with Amazon® S3/CloudFront.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-s2stream-mp3-rtmp.x-php")).'</p>'."\n";
517
 
518
- echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp3-rtmp-only\').toggle(); return false;" class="ws-dotted-link">JW Player® (RTMP streaming MP3 only, via s2Member\'s Amazon® S3/CloudFront integration)</a></p>'."\n";
519
- echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp3-rtmp-only" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player® here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />Streams with the RTMP protocol only, with no access to the source file, only to the RTMP stream.<br />This requires s2Member to be integrated with Amazon® S3/CloudFront.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-s2stream-mp3-rtmp-only.x-php")).'</p>'."\n";
520
 
521
  echo '<div class="ws-menu-page-hr"></div>'."\n";
522
 
523
- echo '<h3>PHP Code Examples (for more advanced integrations via PHP — in WordPress® themes)</h3>'."\n";
524
 
525
- echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-standard-mp4\').toggle(); return false;" class="ws-dotted-link">JW Player® (MP4 file, via Rewrite URLs. Amazon® S3/CloudFront NOT required)</a></p>'."\n";
526
- echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-standard-mp4" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player® here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This does NOT require s2Member to be integrated with Amazon® S3/CloudFront.<br />Also see: <code>s2Member -› Download Options -› Advanced Mod Rewrite Linkage</code>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-standard-mp4.x-php")).'</p>'."\n";
527
 
528
- echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-streaming-mp4\').toggle(); return false;" class="ws-dotted-link">JW Player® (RTMP streaming MP4, via s2Member\'s Amazon® S3/CloudFront integration)</a></p>'."\n";
529
- echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-streaming-mp4" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player® here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This requires s2Member to be integrated with Amazon® S3/CloudFront.<br />Also see: <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-summary/" target="_blank" rel="external">s2Member Codex -› API Functions</a>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-streaming-mp4.x-php")).'</p>'."\n";
530
 
531
- echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-streaming-mp4-sca\').toggle(); return false;" class="ws-dotted-link">JW Player® (RTMP streaming MP4, via s2Member\'s JSON/Shortcode alternative)</a></p>'."\n";
532
- echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-streaming-mp4-sca" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player® here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This requires s2Member to be integrated with Amazon® S3/CloudFront.<br />Also see: <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-summary/" target="_blank" rel="external">s2Member Codex -› API Functions</a>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-streaming-mp4-sca.x-php")).'</p>'."\n";
533
 
534
- echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-streaming-mp4-webm\').toggle(); return false;" class="ws-dotted-link">JW Player® (RTMP streaming MP4, advanced w/ multiple fallbacks)</a></p>'."\n";
535
- echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-streaming-mp4-webm" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player® here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This requires s2Member to be integrated with Amazon® S3/CloudFront.<br />Also see: <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-summary/" target="_blank" rel="external">s2Member Codex -› API Functions</a>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-streaming-mp4-webm.x-php")).'</p>'."\n";
536
 
537
  echo '</div>'."\n";
538
 
@@ -545,31 +547,31 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
545
  {
546
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_before_rtmp_streaming", get_defined_vars());
547
 
548
- echo '<div class="ws-menu-page-group" title="JW Player® v5 &amp; RTMP Protocol Examples (Deprecated)">'."\n";
549
 
550
  echo '<div class="ws-menu-page-section ws-plugin--s2member-rtmp-streaming-section">'."\n";
551
- echo '<h3>JW Player® v5 &amp; RTMP Protocol Examples (Deprecated)</h3>'."\n";
552
  echo '<a href="http://www.longtailvideo.com/players/" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/jwplayer-logo.png" class="ws-menu-page-right" style="width:179px; height:58px; border:0;" alt="." /></a>'."\n";
553
- echo '<p>While it is possible to serve audio/video files protected by s2Member, without needing to integrate Amazon® S3 or CloudFront; we DO highly recommend that you integrate both Amazon® S3 and Amazon® CloudFront in order to maximize speed and compatibility across various viewing platforms. That being said, there are code samples below that will serve audio/video files both with and without Amazon® S3/CloudFront. You can also check the <a href="'.esc_attr(c_ws_plugin__s2member_readmes::parse_readme_value("Forum URI")).'" target="_blank" rel="external">s2Member Support Forums</a> for tips/tricks if you like.</p>'."\n";
554
- echo '<p><strong>One of the great things about Amazon® CloudFront</strong>, is its ability to <strong>stream/seek media files</strong> in the truest sense of the word. For sites delivering protected <em>FLV/MP4/OGG/WEBM</em> and other streaming audio/video file types over the <em>RTMP</em> protocol, Amazon® CloudFront is our recommendation. Once you\'ve successfully configured s2Member to use both Amazon® S3 and Amazon® CloudFront together, please review the code samples below. s2Member can automatically serve your protected files over the <em>RTMP</em> protocol using an Amazon® CloudFront Streaming Distribution.</p>'."\n";
555
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_rtmp_streaming", get_defined_vars());
556
 
557
  echo '<div class="ws-menu-page-hr"></div>'."\n";
558
 
559
  echo '<h3>PHP Code Examples (for more advanced integrations)</h3>'."\n";
560
- echo '<p>These examples exist from past versions of s2Member. JW Player® v5 is now outdated by JW Player® v6 (recommended).</p>'."\n";
561
 
562
- echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-standard-mp4\').toggle(); return false;" class="ws-dotted-link">JW Player® (MP4 file, via Rewrite URLs. Amazon® S3/CloudFront NOT required)</a></p>'."\n";
563
- echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-standard-mp4" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player® here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This does NOT require s2Member to be integrated with Amazon® S3/CloudFront.<br />Also see: <code>s2Member -› Download Options -› Advanced Mod Rewrite Linkage</code>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-v5-standard-mp4.x-php")).'</p>'."\n";
564
 
565
- echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-streaming-mp4\').toggle(); return false;" class="ws-dotted-link">JW Player® (RTMP streaming MP4, via s2Member\'s Amazon® S3/CloudFront integration)</a></p>'."\n";
566
- echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-streaming-mp4" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player® here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This requires s2Member to be integrated with Amazon® S3/CloudFront.<br />Also see: <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-summary/" target="_blank" rel="external">s2Member Codex -› API Functions</a>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-v5-streaming-mp4.x-php")).'</p>'."\n";
567
 
568
- echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-streaming-mp4-sca\').toggle(); return false;" class="ws-dotted-link">JW Player® (RTMP streaming MP4, via s2Member\'s JSON/Shortcode alternative)</a></p>'."\n";
569
- echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-streaming-mp4-sca" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player® here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This requires s2Member to be integrated with Amazon® S3/CloudFront.<br />Also see: <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-summary/" target="_blank" rel="external">s2Member Codex -› API Functions</a>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-v5-streaming-mp4-sca.x-php")).'</p>'."\n";
570
 
571
- echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-streaming-mp4-webm\').toggle(); return false;" class="ws-dotted-link">JW Player® (RTMP streaming MP4, advanced w/ multiple fallbacks)</a></p>'."\n";
572
- echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-streaming-mp4-webm" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player® here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This requires s2Member to be integrated with Amazon® S3/CloudFront.<br />Also see: <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-summary/" target="_blank" rel="external">s2Member Codex -› API Functions</a>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-v5-streaming-mp4-webm.x-php")).'</p>'."\n";
573
 
574
  echo '</div>'."\n";
575
 
@@ -594,7 +596,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
594
  echo '<p>Or, if you really want to get advanced, you could do something like this:<br /><code>... /wp-content/plugins/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'<strong class="ws-menu-page-hilite">/s2member-file-inline-[yes|no]/s2member-file-download-key-[key]</strong>/example-file.zip</code><br /><code>... /wp-content/plugins/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'<strong class="ws-menu-page-hilite">/s2member-file-inline-yes/s2member-file-download-key-xS54df5ER4d5x</strong>/example-file.zip</code><br /><code>... /wp-content/plugins/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'<strong class="ws-menu-page-hilite">/s2member-file-inline-yes/s2member-skip-confirmation</strong>/example-file.zip</code></p>'."\n";
595
  echo '<p>Or even this, if you\'re using Remote Header Authorization:<br /><code>... /wp-content/plugins/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'<strong class="ws-menu-page-hilite">/s2member-file-remote</strong>/example-file.zip</code></p>'."\n";
596
  echo '<p>Specifying storage location option dynamically:<br /><code>... /wp-content/plugins/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'<strong class="ws-menu-page-hilite">/s2member-file-storage-[local|s3|cf]</strong>/example-file.zip</code><br /><code>... /wp-content/plugins/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'<strong class="ws-menu-page-hilite">/s2member-file-storage-cf</strong>/example-cloudfront-file.zip</code><br /><code>... /wp-content/plugins/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'<strong class="ws-menu-page-hilite">/s2member-file-storage-s3/s2member-file-inline</strong>/example-s3-file.html</code></p>'."\n";
597
- echo '<p><em>* Note, the order of your s2Member-specific parameters with Advanced Mod-Rewrite Linkage is irrelevant. Feel free to add/remove, or even change the order. Everything discussed here is also Multisite compatible. Everything discussed here is also compatible when/if combined with Amazon® S3/CDN Storage. However, NONE of this will work on servers that do NOT support <code>mod_rewrite</code>. Almost all web servers do though.</em></p>'."\n";
598
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_rewrite_linkage", get_defined_vars());
599
  echo '</div>'."\n";
600
 
@@ -611,7 +613,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
611
 
612
  echo '<div class="ws-menu-page-section ws-plugin--s2member-shortcode-attrs-section">'."\n";
613
  echo '<h3>Shortcode Attributes &amp; API Functions (Explained In Full Detail)</h3>'."\n";
614
- echo '<p>s2Member makes <a href="http://codex.wordpress.org/Shortcode_API#Overview" target="_blank" rel="external">Shortcodes</a> available to you, which allow you to generate File Download URLs and/or File Download Keys. Like most Shortcodes for WordPress®, s2Member reads Attributes in your Shortcode. Many site owners like to know exactly how these Shortcode Attributes work. Below, is a brief overview of each possible Shortcode Attribute.</p>'."\n";
615
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_shortcode_attrs", get_defined_vars());
616
 
617
  echo '<div class="ws-menu-page-hr"></div>'."\n";
@@ -624,20 +626,20 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
624
 
625
  echo '<td style="padding-top:0;">'."\n";
626
  echo '<ul>'."\n";
627
- echo '<li><code>download="file.zip"</code> Location of the file, relative to the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory; or, relative to the root of your Amazon® S3 Bucket, when applicable.</li>'."\n";
628
  echo '<li><code>download_key="no"</code> Defaults to <code>no</code>. If <code>download_key="1|on|yes|true|ip-forever|universal"</code>, s2Member will return a URL with an s2Member-generated File Download Key. You don\'t need to generate the File Download Key yourself, s2Member does it for you. If you set <code>download_key="ip-forever"</code>, the File Download Key that s2Member generates will last forever, for a specific IP Address; otherwise, by default, all File Download Keys expire after 24 hours automatically. If you set <code>download_key="universal"</code>, s2Member will generate a File Download Key that is good for anyone/everyone forever, with NO restrictions on who/where/when a file is accessed <em>(e.g. be careful with this one)</em>.</li>'."\n";
629
- echo '<li><code>stream="no"</code> Defaults to <code>no</code> with <code>[s2File /]</code> Shortcode. Defaults to <code>yes</code> with <code>[s2Stream /]</code> Shortcode. If <code>stream="1|on|yes|true"</code>, s2Member will return a URL containing a parameter/directive, which forces the File Download to take place over the RTMP protocol if at all possible. This ONLY works when/if s2Member is configured to run with both Amazon® S3/CloudFront. Please note however, it\'s better to use the example code provided in the section above, regarding: <code>JW Player® and the RTMP Protocol</code>. Also note, if <code>get_streamer_json="1|on|yes|true"</code>, s2Member will automatically force <code>stream="yes"</code> for you.</li>'."\n";
630
- echo '<li><code>inline=""</code> Defaults to <code>[empty]</code> with <code>[s2File /]</code> Shortcode. Defaults to <code>yes</code> with <code>[s2Stream /]</code> Shortcode. If <code>inline="1|on|yes|true"</code>, s2Member will serve the file inline, instead of as an actual File Download. If empty, s2Member will look at your <code>Inline File Extensions</code> configuration above, and serve the file inline; if, and only if, its extension matches one found in your configuration. By default, s2Member serves all files as attachments <em>(i.e. downloads)</em>, except in the case of the <code>[s2Stream /]</code> Shortcode where this defaults to <code>yes</code>. Please read the section above regarding <code>Inline File Extensions</code> for further details. Also note, this Shortcode Attribute does NOTHING for files served via Amazon® CloudFront. See the tech-notes listed in the Amazon® CloudFront section for further details and workarounds.</li>'."\n";
631
- echo '<li><code>storage=""</code> Defaults to <code>[empty]</code>. If <code>storage="local|s3|cf"</code>, s2Member will serve the file from a specific source location, based on the value of this Shortcode Attribute. For example, if you\'ve configured Amazon® S3 and/or CloudFront; but, there are a few files that you want to upload locally to the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory; you can force s2Member to serve a file from local storage by setting <code>storage="local"</code> explicitly.</li>'."\n";
632
  echo '<li><code>remote="no"</code> Defaults to <code>no</code>. If <code>remote="1|on|yes|true"</code>, s2Member will authenticate access to the File Download via Remote Header Authorization, instead of through your web site. This is similar to <code>.htaccess</code> protection routines of yester-year</code>. Please check the <code>Remote Authorization and Podcasting</code> section for further details about how this works.</li>'."\n";
633
  echo '<li><code>ssl=""</code> Defaults to <code>[empty]</code>. If <code>ssl="1|on|yes|true"</code>, s2Member will generate a File Download URL with an SSL protocol <em>(i.e. the URL will start with <code>https://</code> or <code>rtmpe://</code>)</em>. If empty, s2Member will only generate a File Download URL with an SSL protocol, when/if the Post/Page/URL firing the Shortcode itself, is also being viewed over SSL. Otherwise, s2Member will use a non-SSL protocol by default.</li>'."\n";
634
- echo '<li><code>rewrite="no"</code> Defaults to <code>no</code> with <code>[s2File /]</code> Shortcode. Defaults to <code>yes</code> with <code>[s2Stream /]</code> Shortcode. If <code>rewrite="1|on|yes|true"</code>, s2Member will generate a File Download URL that takes full advantage of s2Member\'s Advanced Mod Rewrite functionality. If you\'re running an Apache web server, or another server that supports <code>mod_rewrite</code>, we highly recommend turning this on. s2Member\'s <code>mod_rewrite</code> URLs do NOT contain query string parameters, making them more portable/compatible with other software applications and/or plugins for WordPress®. If you\'re integrating with JW Player®, you MUST use <code>rewrite="yes"</code>.</li>'."\n";
635
- echo '<li><code>rewrite_base=""</code> Defaults to <code>[empty]</code>. If <code>rewrite_base="'.esc_attr(site_url("/")).'"</code>, s2Member will generate a File Download URL that takes full advantage of s2Member\'s Advanced Mod Rewrite functionality, and it will use the rewrite base URL as a prefix. This could be useful on some WordPress® installations that use advanced directory structures. It could also be useful for site owners using virtual directories that point to <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code>. Note, if <code>rewrite_base</code> is set, s2Member will automatically force <code>rewrite="yes"</code> for you.</li>'."\n";
636
  echo '<li><code>skip_confirmation="no"</code> Defaults to <code>no</code>. If <code>skip_confirmation="1|on|yes|true"</code>, s2Member will generate a File Download URL which contains a directive, telling s2Member NOT to introduce any JavaScript confirmation prompts on your site, for this File Download URL. Please note, s2Member will automatically detect links, anywhere in your content, and/or anywhere in your theme files, that contain <code>s2member_file_download</code> or <code>s2member-files</code>. Whenever a logged-in Member clicks a link that contains <code>s2member_file_download</code> or <code>s2member-files</code>, the system will politely ask the User to confirm the download using a very intuitive JavaScript confirmation prompt, which contains specific details about your configured download limitations. This way your Members will be aware of how many files they\'ve downloaded in the current period; and they\'ll be able to make a conscious decision about whether to proceed with a specific download or not.</li>'."\n";
637
- echo '<li><code>url_to_storage_source="no"</code> Defaults to <code>no</code> with <code>[s2File /]</code> Shortcode. Defaults to <code>yes</code> with <code>[s2Stream /]</code> Shortcode. If <code>url_to_storage_source="1|on|yes|true"</code>, s2Member will generate a File Download URL which points directly to the storage source. This is only functional with Amazon® S3 and/or CloudFront integrations. If you create a URL that points directly to the storage source <em>(i.e. points directly to Amazon® S3 or CloudFront)</em>, s2Member will NOT be able to further authenticate the current User/Member; and, s2Member will NOT be able to count the File Download against the current User\'s account record, because the URL being generated does not pass back through s2Member at all, it points directly to the storage source. For this reason, if you set <code>url_to_storage_source="true"</code>, you should also set <code>check_user="true"</code> and <code>count_against_user="true"</code>, telling s2Member to authenticate the current User, and if authenticated, count this File Download URL against the current User\'s account record in real-time <em>(i.e. as the URL is being generated) </em>, while it still has a chance to do so. This Shortcode Attribute is useful when you stream files over the RTMP protocol; where an <code>http://</code> URL is not feasible. It also helps in situations where a 3rd-party software application will not work as intended, with s2Member\'s internal redirection to Amazon® S3/CloudFront files. Important, when <code>check_user="true"</code> and/or <code>count_against_user="true"</code>, the Shortcode will return an empty and/or null object value in situations where the current User/Member does NOT have access to the file.</li>'."\n";
638
  echo '<li><code>count_against_user="no"</code> Defaults to <code>no</code> with <code>[s2File /]</code> Shortcode. Defaults to <code>yes</code> with <code>[s2Stream /]</code> Shortcode. If <code>count_against_user="1|on|yes|true"</code>, it will automatically force <code>check_user="true"</code> as well. In other words, s2Member will authenticate the current User, and if authenticated, count this File Download URL against the current User\'s account record in real-time <em>(i.e. as the URL is being generated) </em>. This is off by default with the <code>[s2File /]</code> Shortcode. By default, s2Member will simply generate a File Download URL, and upon a User/Member clicking the URL, s2Member will authenticate the User/Member at that time, count the File Download against their account record, and serve the File Download. In other words, under normal circumstances, there is no reason to set <code>check_user="true"</code> and/or <code>count_against_user="true"</code> when generating the URL itself. However, this is a useful Shortcode Attribute when <code>url_to_storage_source="true"</code>. Please note, when <code>check_user="true"</code> and/or <code>count_against_user="true"</code>, the Shortcode will return an empty and/or null object value in situations where the current User/Member does NOT have access to the file.</li>'."\n";
639
  echo '<li><code>check_user="no"</code> Defaults to <code>no</code> with <code>[s2File /]</code> Shortcode. Defaults to <code>yes</code> with <code>[s2Stream /]</code> Shortcode. If <code>check_user="1|on|yes|true"</code>, s2Member will authenticate the current User before allowing the File Download URL to be generated. This is off by default with the <code>[s2File /]</code> Shortcode. By default, s2Member will simply generate a File Download URL, and upon a User/Member clicking the URL, s2Member will authenticate the User/Member at that time, and serve the File Download to the User/Member. In other words, under normal circumstances, there is no reason to set <code>check_user="true"</code> and/or <code>count_against_user="true"</code> when generating the URL itself. However, this IS a useful Shortcode Attribute when <code>url_to_storage_source="true"</code>. Please note, when <code>check_user="true"</code> and/or <code>count_against_user="true"</code>, the Shortcode will return an empty and/or null object value in situations where the current User/Member does NOT have access to the file.</li>'."\n";
640
- echo '<li><code>get_streamer_json="no"</code> Defaults to <code>no</code>. N/A with <code>[s2Stream /]</code> Shortcode. If <code>get_streamer_json="1|on|yes|true"</code>, the <code>[s2File /]</code> Shortcode will return a JSON object for JavaScript notation, making it possible to integrate the <code>[s2File /]</code> Shortcode into JavaScript routines that configure streaming media players. For further details, please review the section above: <code>JW Player® &amp; RTMP Protocol Examples</code>. Note, if you set <code>get_streamer_json="true"</code>, s2Member will automatically force <code>url_to_storage_source="true"</code> and <code>stream="true"</code>. For that reason, you should carefully review the details and warning above regarding <code>url_to_storage_source</code>. If you set <code>get_streamer_json="true"</code>, you should also set <code>check_user="true"</code> and <code>count_against_user="true"</code>.</li>'."\n";
641
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_shortcode_attrs_s2file_lis", get_defined_vars());
642
  echo '</ul>'."\n";
643
  echo '</td>'."\n";
@@ -649,7 +651,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
649
  echo '<div class="ws-menu-page-hr"></div>'."\n";
650
 
651
  echo '<h4 style="margin:0;">Additional <code>[s2Stream /]</code> Shortcode Attributes:</h4>'."\n";
652
- echo '<p style="margin:0;"><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/jwplayer-s2stream-shortcodes/" target="_blank" rel="external">JW Player® w/ <code>[s2Stream /]</code> Shortcodes</a>.</p>'."\n";
653
  echo '<p style="margin:0;"><strong>See also:</strong> API Function <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-functions/#src_doc_s2member_file_download_url()" target="_blank" rel="external">s2member_file_download_url()</a> for PHP integration.</p>'."\n";
654
  echo '<table class="form-table" style="margin-top:0;">'."\n";
655
  echo '<tbody>'."\n";
@@ -657,12 +659,12 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
657
 
658
  echo '<td style="padding-top:0;">'."\n";
659
  echo '<ul>'."\n";
660
- echo '<li><code>file_download="video.mp4"</code> Location of the audio/video file, relative to the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory; or, relative to the root of your Amazon® S3 Bucket, when applicable.</li>'."\n";
661
- echo '<li><code>player="jwplayer-v6-rtmp"</code> Required. Current supported players in this Shortcode include: <code>jwplayer-v6</code> (works with any audio/video file, and you do NOT need to have Amazon® S3 or CloudFront integrated for this to work), <code>jwplayer-v6-rtmp</code> (streams with the RTMP protocol, plus there is a full download fallback of the source file if streaming is not possible on a particular device; this requires both Amazon® S3 and CloudFront integration), <code>jwplayer-v6-rtmp-only</code> (streams with the RTMP protocol only, with no access to the source file, only to the RTMP stream; this requires both Amazon® S3 and CloudFront integration).</li>'."\n";
662
- echo '<li><code>player_id=""</code> Optional. HTML div ID for the audio/video player. Defaults to a unique ID generated by s2Member® for each instance of your Shortcode.</li>'."\n";
663
  echo '<li><code>player_path="/jwplayer/jwplayer.js"</code> Required. Path to the player\'s JavaScript file (ex: <code>/jwplayer/jwplayer.js</code> — you should upload the <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">/jwplayer</a> folder to the root of your web directory).</li>'."\n";
664
- echo '<li><code>player_{setting}=""</code> Optional. Any additional configuration attributes supported by your audio/video player, prefixed with <code>player_</code>. For JW Player v6, see <a href="http://www.longtailvideo.com/support/jw-player/28839/embedding-the-player" target="_blank" rel="external">this article please</a>. Examples: <code>player_width="480"</code>, <code>player_height="270"</code>, <code>player_title="My Video"</code>, <code>player_description="A video about something."</code>, <code>player_image="http://www.example.com/wp-content/uploads/video-preview.jpg"</code>, <code>player_mediaid="video_ei0wsx23"</code>, <code>player_autostart="true"</code>, <code>player_skin="/jwplayer/my-skin.xml"</code>, <code>player_key="my-license-key"</code>, <code>player_captions="{file:\'/assets/captions-en.vtt\',label:\'English\'}"</code> (<em>With <a href="http://www.longtailvideo.com/support/jw-player/28845/adding-video-captions" target="_blank" rel="external">Captions</a>, you can exclude the square array brackets to avoid Shortcode parsing issues. s2Member® will automatically wrap your Caption objects with square array brackets.</em>). Please note that "Advanced Options Blocks" listed on <a href="http://www.longtailvideo.com/support/jw-player/28839/embedding-the-player" target="_blank" rel="external">this page</a> are NOT supported here. For those, please use: <code>player_option_blocks=""</code> (see below).</li>'."\n";
665
- echo '<li><code>player_option_blocks=""</code> Optional. Any "Advanced Option Blocks" supported by your audio/video player. For JW Player v6, see <a href="http://www.longtailvideo.com/support/jw-player/28839/embedding-the-player" target="_blank" rel="external">this article please</a>. Here are some examples: <code>player_option_blocks="sharing:{}"</code>, <code>player_option_blocks="sharing:{}, logo: {file: \'/logo.png\', link: \'http://example.com\'}"</code>. Or: <code>player_option_blocks="c2hhcmluZzoge30="</code> (base64 encoded version of <code>sharing:{}</code>). Please note that "Advanced Options Blocks" can be defined in plain text or with a <a href="http://www.base64encode.org/" target="_blank" rel="external">base64 encoded string</a>. Advanced Option Blocks are JavaScript objects with properties. If you have trouble defining JavaScript object properties inside a Shortcode Attribute, please use <a href="http://www.base64encode.org/" target="_blank" rel="external">this tool</a> to base64 encode your Advanced Option Blocks, so that you end up with a string that\'s compatible with Shortcode Attributes.</li>'."\n";
666
  echo '<li>Please check the <strong>Shortcode Attributes</strong> Tab in <a href="http://www.s2member.com/kb/jwplayer-s2stream-shortcodes/#using-s2stream-shortcodes" target="_blank" rel="external">this KB article</a> for further details on everything here.</li>'."\n";
667
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_shortcode_attrs_s2stream_lis", get_defined_vars());
668
  echo '</ul>'."\n";
@@ -682,7 +684,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
682
 
683
  echo '<td style="padding-top:0;">'."\n";
684
  echo '<ul>'."\n";
685
- echo '<li><code>file_download="file.zip"</code> Location of the file, relative to the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory; or, relative to the root of your Amazon® S3 Bucket, when applicable.</li>'."\n";
686
  echo '<li><code>directive=""</code> Defaults to <code>[empty]</code>. If <code>directive="ip-forever|universal"</code>, s2Member will return a special File Download Key. If you set <code>directive="ip-forever"</code>, the File Download Key that s2Member generates will last forever, for a specific IP Address; otherwise, by default, all File Download Keys expire after 24 hours automatically. If you set <code>directive="universal"</code>, s2Member will generate a File Download Key that is good for anyone/everyone forever, with NO restrictions on who/where/when a file is accessed <em>(e.g. be careful with this one)</em>.</li>'."\n";
687
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_shortcode_attrs_s2key_lis", get_defined_vars());
688
  echo '</ul>'."\n";
@@ -706,14 +708,14 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
706
 
707
  echo '<div class="ws-menu-page-section ws-plugin--s2member-gzip-conflicts-section">'."\n";
708
  echo '<h3>Preventing GZIP Conflicts On Server (Instructions)</h3>'."\n";
709
- echo '<p>Protected files served by s2Member® through PHP scripts, are already compressed. Therefore, <a href="http://code.google.com/speed/articles/gzip.html" target="_blank" rel="nofollow external xlink">GZIP compression</a> is not needed during protected file delivery. Some web servers (i.e. Apache, LiteSpeed, and similar) include GZIP compression rules through server-side extensions, like <code>mod_deflate</code> for example. While s2Member® encourages the use of extensions like <code>mod_deflate</code>, it is best to disable GZIP automatically (i.e. temporarily) during s2Member\'s delivery of a protected file through a PHP script. This avoids conflicts on the server which might otherwise lead to corrupted file downloads. s2Member® makes a valiant effort to accomplish this via PHP, all on its own. However, it never hurts to add this section of code to the root <code>.htaccess</code> file for your WordPress® installation. Optional, but highly recommended.</p>'."\n";
710
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_gzip_conflicts", get_defined_vars());
711
 
712
  echo '<div class="ws-menu-page-hr"></div>'."\n";
713
- echo '<p style="margin:0; font-weight:bold;">s2Member® automatically adds this to your <code>.htaccess</code> file upon activation of the plugin.</p>'."\n";
714
  echo '<p style="margin:0;">The following <code>mod_rewrite</code> rule goes inside this file: <code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path(ABSPATH.".htaccess")).'</code></p>'."\n";
715
  echo '<pre><code>'.esc_html(trim(c_ws_plugin__s2member_utilities::evl(file_get_contents($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_no_gzip_htaccess"])))).'</code></pre>';
716
- echo '<p><strong>* Tip:</strong> this covers all types of integration with s2Member® File Downloads, even if you\'re using s2Member\'s Advanced Mod Rewrite Linkage.</p>'."\n";
717
  echo '</div>'."\n";
718
 
719
  echo '</div>'."\n";
@@ -729,7 +731,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_down_ops"))
729
 
730
  echo '<div class="ws-menu-page-section ws-plugin--s2member-custom-capability-files-section">' . "\n";
731
  echo '<h3>Restricting Files, Based On Custom Capabilities</h3>' . "\n";
732
- echo '<p>If you\'re NOT familiar with Custom Capabilities yet, please read: <code>Dashboard -› s2Member® -› API Scripting -› Custom Capability Packages</code>. Once you understand the basic concept of Custom Capabilities &amp; Protected File Downloads, you\'ll see that (by default) s2Member does NOT handle File Download Protection with respect to Custom Capabilities. That\'s where Custom Capability Sub-directories come in.</p>' . "\n";
733
  echo '<p>You can create Custom Capability Sub-directories under: <code>' . esc_html (c_ws_plugin__s2member_utils_dirs::doc_root_path ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])) . '</code>. For instance, if you have a Custom Capability <code>music</code>, you can place protected files that should ONLY be accessible to Members with <code>access_s2member_ccap_music</code>, inside: <code>/' . esc_html (c_ws_plugin__s2member_utils_dirs::basename_dir_app_data ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])) . '/access-s2member-ccap-music/</code>. Some examples are provided below.</p>' . "\n";
734
  do_action ("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_custom_capability_files", get_defined_vars ());
735
 
32
  echo '<div class="wrap ws-menu-page">'."\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>'."\n";
35
+ echo '<h2>s2Member File Download Options</h2>'."\n";
36
 
37
  echo '<table class="ws-menu-page-table">'."\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">'."\n";
115
 
116
  echo '<div class="ws-menu-page-section ws-plugin--s2member-limit-exceeded-page-section">'."\n";
117
  echo '<h3>Download Limit Exceeded Page (required, if providing access to protected files)</h3>'."\n";
118
+ echo '<p>This Page will be shown when/if a Member reaches their download limit, based on your configuration of <strong>Basic Download Restrictions</strong> above. This Page should be created by you, in WordPress. This Page should provide an informative message to the Member, describing your file access restrictions. Just tell them a little bit about your policy on file downloads, and why they might have reached this Page.</p>'."\n";
119
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_limit_exceeded_page", get_defined_vars());
120
 
121
  echo '<table class="form-table">'."\n";
235
  echo '<div class="ws-menu-page-section ws-plugin--s2member-remote-authorization-section">'."\n";
236
  echo '<h3>Remote Header Authorization (optional)</h3>'."\n";
237
  echo '<p>This can be enabled on a case-by-case basis. Just add this to the end of your download links: <code>&amp;s2member_file_remote=yes</code>. Shortcode alternative: <code>[s2File download="example-file.zip" remote="yes" /]</code>.</p>'."\n";
238
+ echo '<p>Remote Header Authorization allows access to file downloads through an entirely different approach. Instead of asking the Member to log into your site through a browser, a Member will be prompted automatically, to log in through HTTP Header Authorization prompts; which is the same technique used in more traditional security systems via .htaccess files. In other words, Remote Header Authorization makes it possible for your Members to access files through remote applications that may NOT use a browser. This is often the case when a Member needs to access protected files through a software client like iTunes; typical with podcasts. See <a href="http://www.s2member.com/videos/71F49478D6983A9C/" target="_blank" rel="external">tutorial video here</a> for details about how to setup a Podcast for iTunes.</p>'."\n";
239
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_remote_authorization", get_defined_vars());
240
  echo '</div>'."\n";
241
 
248
  {
249
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_before_amazon_s3", get_defined_vars());
250
 
251
+ echo '<div class="ws-menu-page-group" title="Amazon S3/CDN Storage Option"'.((c_ws_plugin__s2member_menu_pages::$pre_display_errors["cf_files_auto_configure_distros"]) ? ' default-state="open"' : '').'>'."\n";
252
 
253
  echo '<div class="ws-menu-page-section ws-plugin--s2member-amazon-s3-section">'."\n";
254
+ echo '<h3>Amazon S3/CDN Storage &amp; Delivery (optional)</h3>'."\n";
255
  echo '<a href="http://aws.amazon.com/s3/" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/amazon-logo.png" class="ws-menu-page-right" style="width:250px; height:100px; border:0;" alt="." /></a>'."\n";
256
+ echo '<p>Please note, all of this is optional. s2Member can be configured here to ONLY use Amazon S3 <em>(i.e. without Amazon CloudFront)</em>. Or, s2Member can be configured to use BOTH Amazon S3 and Amazon CloudFront together. If you want to use Amazon S3 Storage, but you don\'t care about Amazon CloudFront, feel free to leave the entire Amazon CloudFront section empty. The configuration options in the Amazon CloudFront section are ONLY required if you are planning to use both Amazon S3 and Amazon CloudFront together.</p>'."\n";
257
+ echo '<p>Amazon Simple Storage Service (<a href="http://aws.amazon.com/s3/" target="_blank" rel="external">Amazon S3</a>). Amazon S3 is storage for the Internet. It is designed to make web-scale computing easier for developers. Amazon S3 provides a simple web services interface that can be used to store and retrieve any amount of data, at any time, from anywhere on the web. It gives developers access to the same highly scalable, reliable, secure, fast, inexpensive infrastructure that Amazon uses to run its own global network of web sites. s2Member has been integrated with Amazon S3, so that <em>(if you wish)</em>, instead of using the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory, you can store all of your protected files inside an Amazon S3 Bucket.</p>'."\n";
258
+ echo '<p>If you configure the options below, s2Member will assume all protected files are inside your Amazon S3 Bucket; and the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory is no longer used at all. That being said, all other aspects of s2Member\'s File Download protection remain the same. The only thing that changes, is the location of your protected files. In other words, Basic Download Restrictions, Download Keys, Inline Extensions, Custom Capability and/or Membership Level Files will all continue to work just as before. The only difference is that s2Member will use your Amazon S3 Bucket as a CDN <em>(i.e. Content Delivery Network)</em> instead of the local <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory.</p>'."\n";
259
+ echo '<p>s2Member assumes that you\'re creating a new Amazon S3 Bucket, specifically for this installation; and that your Bucket is NOT available publicly. In other words, if you type this URL into your browser <em>(i.e. <code>http://your-bucket-name.s3.amazonaws.com/</code>)</em>, you should get an error that says: <code>Access Denied</code>. That\'s good, that\'s exactly what you want. You can create your Amazon S3 Bucket using the <a href="https://console.aws.amazon.com/s3/home" target="_blank" rel="external">Amazon interface</a>. Or, some people prefer to use this popular Firefox extension (<a href="http://www.s3fox.net/" target="_blank" rel="external">S3 Fox Organizer</a>).</p>'."\n";
260
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_amazon_s3", get_defined_vars());
261
 
262
  echo '<div class="ws-menu-page-hr"></div>'."\n";
263
 
264
+ echo '<p><em><strong>Dev Note w/Technical Details:</strong> s2Member uses "Digitally Signed URLs", authenticated by the Amazon S3 API. Documented for developers <a href="http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?RESTAuthentication.html" target="_blank" rel="external">here</a>. To put it simply, s2Member will generate Amazon S3 URLs (internally); which allow Customers temporary access to specific files inside your S3 Bucket. s2Member\'s Digitally Signed URLs leading to Amazon S3, give a Customer 24 hours to connect to the file inside your S3 Bucket. This connection period of 24 hours is largely irrelevant when used in combination with s2Member, because access is renewed for another 24 hours each time you make a file available to a User/Member, and they are authenticated by your configuration of s2Member. This connection period of 24 hours is just a secondary line of defense to further prevent the possibility of link sharing. If you need to change this connection timeout of <code>24 hours</code> for some reason (not likely), you can use this WordPress Filter: <code>ws_plugin__s2member_amazon_s3_file_expires_time</code>.</em></p>'."\n";
265
+ echo '<p><em><strong>Linking To Protected Files:</strong> Nothing changes. s2Member\'s integration with Amazon S3 serves protected files through the same links that all s2Member site owners use. For example, you might use: <code>'.esc_html(site_url("/?s2member_file_download=example-file.zip")).'</code>, where <strong>s2member_file_download</strong> = the file, relative to the root of your Amazon S3 Bucket. In other words, just the file name in most cases. s2Member will redirect Users/Members to a digitally signed Amazon S3 URL, which allows them access to a particular file via Amazon S3. For further details, please review this section of your Dashboard: <code>s2Member -› Download Options -› Basic Download Restrictions</code>. Also see: <code>s2Member -› Download Options -› Advanced Mod-Rewrite Linkage</code>.</em></p>'."\n";
266
+ echo '<p><em><strong>Content Type, Disposition &amp; Inline Files:</strong> The query string parameter <code>&amp;s2member_file_inline=yes</code> DOES work for files served directly through Amazon S3. s2Member DOES have control over the <code>Content-Type</code> and <code>Content-Disposition</code> headers for files being served through Amazon S3. However, Amazon CloudFront servers do NOT automatically determine the MIME type for the objects they serve. If you integrate both Amazon S3 and CloudFront, s2Member will NOT have control over headers. Therefore, when you upload a file to your Amazon S3 Bucket, you should set its Content-Type header. Again, with the Amazon S3/CloudFront combination, you MUST configure headers yourself (such as <code>Content-Type: video/webm</code>, or <code>Content-Disposition: inline|attachment</code>) that you want Amazon CloudFront to send for a particular file. It\'s quite easy. You do this by setting <code>Properties -› Metadata (i.e. headers)</code> on a per-file basis, from inside your Amazon S3 Management Console. In short, when you upload a file to your Amazon S3 Bucket, if you want that file to be served a certain way, be sure to configure its <code>Properties -› Metadata</code> accordingly.</em></p>'."\n";
267
 
268
  echo '<div class="ws-menu-page-hr"></div>'."\n";
269
 
273
 
274
  echo '<th style="padding-top:0;">'."\n";
275
  echo '<label for="ws-plugin--s2member-amazon-s3-files-bucket">'."\n";
276
+ echo 'Amazon S3 File Bucket Name (where protected files are):'."\n";
277
  echo '</label>'."\n";
278
  echo '</th>'."\n";
279
 
282
 
283
  echo '<td>'."\n";
284
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_amazon_s3_files_bucket" id="ws-plugin--s2member-amazon-s3-files-bucket" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_bucket"]).'" /><br />'."\n";
285
+ echo 'Your Amazon S3 Bucket will be used, instead of the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory.<br />'."\n";
286
  echo 'Please type the name of your Bucket. Ex: <code>mys3bucket</code>'."\n";
287
  echo '</td>'."\n";
288
 
291
 
292
  echo '<th>'."\n";
293
  echo '<label for="ws-plugin--s2member-amazon-s3-files-access-key">'."\n";
294
+ echo 'Amazon Access Key (Access Key ID):'."\n";
295
  echo '</label>'."\n";
296
  echo '</th>'."\n";
297
 
300
 
301
  echo '<td>'."\n";
302
  echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_amazon_s3_files_access_key" id="ws-plugin--s2member-amazon-s3-files-access-key" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_access_key"]).'" /><br />'."\n";
303
+ echo 'See: <code>Amazon Web Services Account -› Security Credentials -› Access Keys</code>.'."\n";
304
  echo '</td>'."\n";
305
 
306
  echo '</tr>'."\n";
308
 
309
  echo '<th>'."\n";
310
  echo '<label for="ws-plugin--s2member-amazon-s3-files-secret-key">'."\n";
311
+ echo 'Amazon Secret Key (Secret Access Key):'."\n";
312
  echo '</label>'."\n";
313
  echo '</th>'."\n";
314
 
317
 
318
  echo '<td>'."\n";
319
  echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_amazon_s3_files_secret_key" id="ws-plugin--s2member-amazon-s3-files-secret-key" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_s3_files_secret_key"]).'" /><br />'."\n";
320
+ echo 'See: <code>Amazon Web Services Account -› Security Credentials -› Access Keys (leading to: Legacy Security Credentials)</code>.<br />'."\n";
321
+ echo 'Amazon is deprecating Secret Access Keys, but they ARE still required for digitally signed URLs.'."\n";
322
  echo '</td>'."\n";
323
 
324
  echo '</tr>'."\n";
335
  {
336
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_before_amazon_cf", get_defined_vars());
337
 
338
+ echo '<div class="ws-menu-page-group" title="Amazon S3/CloudFront CDN Storage Option"'.((c_ws_plugin__s2member_menu_pages::$pre_display_errors["cf_files_auto_configure_distros"]) ? ' default-state="open"' : '').'>'."\n";
339
 
340
  echo '<div class="ws-menu-page-section ws-plugin--s2member-amazon-cf-section">'."\n";
341
+ echo '<h3>Amazon S3/CloudFront CDN Storage &amp; Delivery (optional)</h3>'."\n";
342
  echo '<a href="http://aws.amazon.com/cloudfront/" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/amazon-logo.png" class="ws-menu-page-right" style="width:250px; height:100px; border:0;" alt="." /></a>'."\n";
343
+ echo '<p>Please note, all of this is optional. s2Member can be configured to ONLY use Amazon S3 <em>(i.e. without Amazon CloudFront)</em>. Or, s2Member can be configured to use BOTH Amazon S3 and Amazon CloudFront together. If you don\'t want to use Amazon CloudFront, please leave this entire section empty. The configuration options in this section are ONLY required if you are planning to use both Amazon S3 and Amazon CloudFront together.</p>'."\n";
344
+ echo '<p>Amazon Simple Storage Service (<a href="http://aws.amazon.com/s3/" target="_blank" rel="external">Amazon S3</a>) combined with <a href="http://aws.amazon.com/cloudfront/" target="_blank" rel="external">Amazon CloudFront</a>. Amazon CloudFront is a web service for content delivery. It integrates with other Amazon Web Services <em>(i.e. Amazon S3 Storage)</em> to give developers and businesses an easy way to distribute content to end users with low latency, and with high data transfer speeds. Amazon CloudFront delivers your static and streaming content using a global network of edge locations. Requests for your Amazon S3 Bucket Objects <em>(i.e. your protected files)</em> are automatically routed to the nearest edge location, so content is delivered with the best possible performance. s2Member has been integrated with both Amazon S3 and with Amazon CloudFront. So <em>(if you wish)</em>, instead of using the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory, you can store all of your protected files inside an Amazon S3 Bucket and serve them via Amazon CloudFront. But again, please understand, the configuration options in this section are ONLY required if you\'re going to use both Amazon S3 &amp; CloudFront together.</p>'."\n";
345
+ echo '<p><strong>One of the great things about Amazon CloudFront</strong>, is its ability to <strong>stream/seek media files</strong> in the truest sense of the word. For sites delivering protected <em>FLV/MP4/OGG/WEBM</em> and other streaming audio/video file types over the <em>RTMP</em> protocol, Amazon CloudFront is our recommendation. Once you\'ve successfully configured s2Member to use both Amazon S3 and Amazon CloudFront together, please review the section below regarding <code>JW Player &amp; RTMP Protocol Examples</code>. s2Member will automatically serve your protected files over the <em>RTMP</em> protocol using an Amazon CloudFront Streaming Distribution.</p>'."\n";
346
+ echo '<p>If you configure the options below, s2Member will assume all protected files are inside your Amazon S3 Bucket; and the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory is no longer used at all. That being said, all other aspects of s2Member\'s File Download protection remain the same. The only thing that changes, is the location of your protected files. In other words, Basic Download Restrictions, Download Keys, Custom Capability and/or Membership Level Files will all continue to work just as before. The only difference is that s2Member will use your Amazon S3 Bucket, automatically connecting it to both of the Amazon CloudFront Distributions, which s2Member auto-configures for you <em>(see below)</em>. In this way, s2Member uses Amazon CloudFront as a CDN <em>(i.e. Content Delivery Network)</em> for your protected files.</p>'."\n";
347
+ echo '<p>s2Member assumes that you\'re creating a new Amazon S3 Bucket, specifically for this installation; and that your Bucket is NOT available publicly. In other words, if you type this URL into your browser <em>(i.e. <code>http://your-bucket-name.s3.amazonaws.com/</code>)</em>, you should get an error that says: <code>Access Denied</code>. That\'s good, that\'s exactly what you want. You can create your Amazon S3 Bucket using the <a href="https://console.aws.amazon.com/s3/home" target="_blank" rel="external">Amazon interface</a>. Or, some people prefer to use this popular Firefox extension (<a href="http://www.s3fox.net/" target="_blank" rel="external">S3 Fox Organizer</a>). You will also need to enable CloudFront inside your Web Services account at Amazon. Don\'t worry about creating or configuring any CloudFront Distributions, s2Member will auto-create and auto-configure those for you, allowing you to serve protected files.</p>'."\n";
348
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_amazon_cf", get_defined_vars());
349
 
350
  echo '<div class="ws-menu-page-hr"></div>'."\n";
351
 
352
+ echo '<p><em><strong>Dev Note w/Technical Details:</strong> s2Member\'s auto-configuration routines for Amazon CloudFront (below), are designed to create &amp; configure various components on your Amazon Web Services account, which are all requirements for you to <a href="http://docs.amazonwebservices.com/AmazonCloudFront/2010-11-01/DeveloperGuide/index.html?HowToPrivateContent.html" target="_blank" rel="external">serve protected files through the Amazon S3/CloudFront combination</a>. These components include: an Origin Access Identity, read permissions for the Origin Access Identity, and two private content Distributions. One private content Distribution for file downloads, and another private content Distribution for streaming media files; both connected to and sourced by your Amazon S3 Bucket. In addition, s2Member will automatically configure an ACL &amp; Policy (i.e. permissions) on your Amazon S3 Bucket to make sure your protected object/files are NOT available to the public.</em></p>'."\n";
353
+ echo '<p><em><strong>Dev Note w/Technical Details:</strong> s2Member uses "Digitally Signed URLs", authenticated by the Amazon CloudFront API. Documented for developers <a href="http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PrivateContent.html" target="_blank" rel="external">here</a>. To put it simply, s2Member will generate Amazon CloudFront URLs (internally); which allow Customers temporary access to specific files inside your S3 Bucket — via CloudFront Distributions. s2Member\'s Digitally Signed URLs leading to Amazon S3/CloudFront, give a Customer 24 hours to connect to the file inside your S3 Bucket. This connection period of 24 hours is largely irrelevant when used in combination with s2Member, because access is renewed for another 24 hours each time you make a file available to a User/Member, and they are authenticated by your configuration of s2Member. This connection period of 24 hours is just a secondary line of defense to further prevent the possibility of link sharing. If you need to change this connection timeout of <code>24 hours</code> for some reason (not likely), you can use this WordPress Filter: <code>ws_plugin__s2member_amazon_cf_file_expires_time</code>.</em></p>'."\n";
354
+ echo '<p><em><strong>Linking To Protected Files:</strong> RTMP streams are special, but nothing else changes. s2Member\'s integration with Amazon S3/CloudFront serves protected files through the same links that all s2Member site owners use. For example, you might use: <code>'.esc_html(site_url("/?s2member_file_download=example-file.zip")).'</code>, where <strong>s2member_file_download</strong> = the file, relative to the root of your Amazon S3 Bucket. In other words, just the file name in most cases. s2Member will redirect Users/Members to a digitally signed Amazon CloudFront URL, which allows them access to a particular file via Amazon CloudFront. For further details, please review this section of your Dashboard: <code>s2Member -› Download Options -› Basic Download Restrictions</code>. Also see: <code>s2Member -› Download Options -› Advanced Mod-Rewrite Linkage</code>. If you\'re streaming audio/video files over the RTMP protocol, please review the section below: <code>JW Player &amp; RTMP Protocol Examples</code>.</em></p>'."\n";
355
+ echo '<p><em><strong>Content Type, Disposition &amp; Inline Files:</strong> An IMPORTANT issue. The query string parameter <code>&amp;s2member_file_inline=yes</code> does NOTHING for files served via Amazon CloudFront. s2Member has NO control over the <code>Content-Type</code> and/or <code>Content-Disposition</code> headers for a file being served through Amazon CloudFront, and CloudFront servers do NOT automatically determine the MIME type for the objects they serve. Therefore, when you upload a file to your Amazon S3 Bucket, you should set its Content-Type header. That is, you MUST configure headers yourself (such as <code>Content-Type: video/webm</code>, or <code>Content-Disposition: inline|attachment</code>) that you want Amazon CloudFront to send for a particular file. It\'s quite easy. You do this by setting <code>Properties -› Metadata (i.e. headers)</code> on a per-file basis, from inside your Amazon S3 Management Console. In short, when you upload a file to your Amazon S3 Bucket, if you want that file to be served a certain way, be sure to configure its <code>Properties -› Metadata</code> accordingly.</em></p>'."\n";
356
+ echo (stripos(PHP_OS, "win") === 0 && c_ws_plugin__s2member_utils_conds::is_localhost()) ? '<p><em><strong>Localhost Developers:</strong> s2Member\'s Amazon CloudFront integration requires the <a href="http://php.net/manual/en/function.openssl-sign.php" target="_blank" rel="external">openssl_sign()</a> function in PHP so it can digitially sign CloudFront URLs. This function is sometimes problematic on localhost servers such as WAMP &amp; EasyPHP. We recommend installing <a href="http://www.slproweb.com/products/Win32OpenSSL.html" target="_blank" rel="external">this lightweight alternative for Windows</a> while you\'re developing. s2Member will automatically find it here: <code>C:\OpenSSL-Win[32/64]\bin\openssl.exe</code>.'.((file_exists("c:\openssl-win32\bin\openssl.exe") || file_exists("c:\openssl-win64\bin\openssl.exe")) ? ' <strong class="ws-menu-page-hilite">( s2Member has detected that OpenSSL-Win[32/64] IS installed in the correct location, thank you! )</strong>' : ' <strong class="ws-menu-page-hilite">(s2Member has detected that OpenSSL-Win[32/64] is NOT currently available)</strong>').'</em></p>'."\n" : '';
357
 
358
  if($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distros_auto_config_status"] === "configured")
359
+ echo '<p><em class="ws-menu-page-hilite"><strong>Your Amazon CloudFront Distributions are: ( ALREADY configured! )</strong></em>'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_downloads_cname"]) ? '<br /><em class="ws-menu-page-hilite">Downloads Distribution CNAME:</em> <em><code>'.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_downloads_cname"]).' &mdash;&raquo; '.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_downloads_dname"]).'</code></em>' : '').(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_streaming_cname"]) ? '<br /><em class="ws-menu-page-hilite">Streaming Distribution CNAME:</em> <em><code>'.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_streaming_cname"]).' &mdash;&raquo; '.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distro_streaming_dname"]).'</code></em>' : '').'</p>'."\n";
360
 
361
  else if(!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_distros_auto_config_status"])
362
+ echo '<p><em class="ws-menu-page-hilite"><strong>Your Amazon CloudFront Distributions are: (NOT yet auto-configured).</strong></em></p>'."\n";
363
 
364
  echo '<div class="ws-menu-page-hr"></div>'."\n";
365
 
369
 
370
  echo '<th style="padding-top:0;">'."\n";
371
  echo '<label for="ws-plugin--s2member-amazon-cf-files-private-key-id">'."\n";
372
+ echo 'Amazon CloudFront Key Pair ID (your Key Pair ID):'."\n";
373
  echo '</label>'."\n";
374
  echo '</th>'."\n";
375
 
378
 
379
  echo '<td>'."\n";
380
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_amazon_cf_files_private_key_id" id="ws-plugin--s2member-amazon-cf-files-private-key-id" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_private_key_id"]).'" data-s-prev-config-value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_private_key_id"]).'" /><br />'."\n";
381
+ echo 'See: <code>Amazon Web Services Account -› Security Credentials -› Key Pairs</code>.'."\n";
382
  echo '</td>'."\n";
383
 
384
  echo '</tr>'."\n";
386
 
387
  echo '<th>'."\n";
388
  echo '<label for="ws-plugin--s2member-amazon-cf-files-private-key-entry">'."\n";
389
+ echo 'Amazon CloudFront Private Key (contents of your <code>pk-[***].pem</code> file):'."\n";
390
  echo '</label>'."\n";
391
  echo '</th>'."\n";
392
 
396
  echo '<td>'."\n";
397
  echo '<input type="hidden" name="ws_plugin__s2member_amazon_cf_files_private_key" id="ws-plugin--s2member-amazon-cf-files-private-key" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_private_key"]).'" data-s-prev-config-value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_private_key"]).'" />'."\n";
398
  echo '<textarea name="ws_plugin__s2member_amazon_cf_files_private_key_entry" id="ws-plugin--s2member-amazon-cf-files-private-key-entry" rows="3" wrap="off" spellcheck="false" style="font-family:Consolas, monospace;">'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["amazon_cf_files_private_key"]).'</textarea><br />'."\n";
399
+ echo 'See: <code>Amazon Web Services Account -› Security Credentials -› Key Pairs</code>.<br />'."\n";
400
  echo '<em>* Note, s2Member needs your <strong>Private Key file</strong>, NOT your Public Key file.</em>'."\n";
401
  echo '</td>'."\n";
402
 
405
 
406
  echo '<th>'."\n";
407
  echo '<label for="ws-plugin--s2member-amazon-cf-files-auto-configure-distros">'."\n";
408
+ echo 'Auto-Configure your Amazon S3/CloudFront combination?'."\n";
409
  echo '</label>'."\n";
410
  echo '</th>'."\n";
411
 
413
  echo '<tr>'."\n";
414
 
415
  echo '<td>'."\n";
416
+ echo '<input type="checkbox" name="ws_plugin__s2member_amazon_cf_files_auto_configure_distros" id="ws-plugin--s2member-amazon-cf-files-auto-configure-distros" value="'.esc_attr(wp_create_nonce("ws-plugin--s2member-amazon-cf-files-auto-configure-distros")).'"'.((c_ws_plugin__s2member_menu_pages::$pre_display_errors["cf_files_auto_configure_distros"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-amazon-cf-files-auto-configure-distros"><strong>Yes</strong>, automatically configure my Amazon CloudFront Distributions &amp; Amazon S3 ACLs for me.</label><br />'."\n";
417
+ echo '<em>s2Member will auto-configure and/or delete &amp; re-configure your Amazon CloudFront Distributions for you.</em>'."\n";
418
  echo '</td>'."\n";
419
 
420
  echo '</tr>'."\n";
436
 
437
  echo '<th>'."\n";
438
  echo '<label for="ws-plugin--s2member-amazon-cf-files-downloads-distro-cname">'."\n";
439
+ echo 'Amazon CloudFront CNAME for File Downloads (optional):'."\n";
440
  echo '</label>'."\n";
441
  echo '</th>'."\n";
442
 
454
 
455
  echo '<th>'."\n";
456
  echo '<label for="ws-plugin--s2member-amazon-cf-files-streaming-distro-cname">'."\n";
457
+ echo 'Amazon CloudFront CNAME for Streaming Files (optional):'."\n";
458
  echo '</label>'."\n";
459
  echo '</th>'."\n";
460
 
482
  {
483
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_before_rtmp_streaming", get_defined_vars());
484
 
485
+ echo '<div class="ws-menu-page-group" title="JW Player v6 &amp; RTMP Protocol Examples">'."\n";
486
 
487
  echo '<div class="ws-menu-page-section ws-plugin--s2member-rtmp-streaming-section">'."\n";
488
+ echo '<h3>JW Player v6 &amp; RTMP Protocol Examples</h3>'."\n";
489
  echo '<a href="http://www.longtailvideo.com/players/" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/jwplayer-logo.png" class="ws-menu-page-right" style="width:179px; height:58px; border:0;" alt="." /></a>'."\n";
490
+ echo '<p>While it is possible to serve audio/video files protected by s2Member, without needing to integrate Amazon S3 or CloudFront; we DO highly recommend that you integrate both Amazon S3 and Amazon CloudFront in order to maximize speed and compatibility across various viewing platforms. That being said, there are code samples below that will serve audio/video files both with and without Amazon S3/CloudFront. You can also check the <a href="'.esc_attr(c_ws_plugin__s2member_readmes::parse_readme_value("Forum URI")).'" target="_blank" rel="external">s2Member Support Forums</a> for tips/tricks if you like.</p>'."\n";
491
+ echo '<p><strong>One of the great things about Amazon CloudFront</strong>, is its ability to <strong>stream/seek media files</strong> in the truest sense of the word. For sites delivering protected <em>FLV/MP4/OGG/WEBM</em> and other streaming audio/video file types over the <em>RTMP</em> protocol, Amazon CloudFront is our recommendation. Once you\'ve successfully configured s2Member to use both Amazon S3 and Amazon CloudFront together, please review the code samples below. s2Member can automatically serve your protected files over the <em>RTMP</em> protocol using an Amazon CloudFront Streaming Distribution.</p>'."\n";
492
+ echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/jwplayer-s2stream-shortcodes/" target="_blank" rel="external">JW Player w/ <code>[s2Stream /]</code> Shortcodes</a>.</p>'."\n";
493
+ if(stripos(wp_get_theme(), 'infocus') !== FALSE)
494
+ echo '<p><strong>Note:</strong> It appears that you\'re using the inFocus WordPress theme. If you experience trouble with the shortcodes below, try wrapping the shortcode in <code>[raw][/raw]</code> tags (e.g., <code>[raw][s2Stream ... /][/raw]</code>).</p>'."\n";
495
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_rtmp_streaming", get_defined_vars());
496
 
497
  echo '<div class="ws-menu-page-hr"></div>'."\n";
498
 
499
  echo '<h3><code>[s2Stream /]</code> Video Shortcode Examples (recommended — it\'s the easiest way)</h3>'."\n";
500
 
501
+ echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp4\').toggle(); return false;" class="ws-dotted-link">JW Player (MP4 file, via Rewrite URLs. Amazon S3/CloudFront NOT required)</a></p>'."\n";
502
+ echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp4" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />Works with any audio/video file. This does NOT require s2Member to be integrated with Amazon S3/CloudFront.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-s2stream-mp4.x-php")).'</p>'."\n";
503
 
504
+ echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp4-rtmp\').toggle(); return false;" class="ws-dotted-link">JW Player (RTMP streaming MP4, via s2Member\'s Amazon S3/CloudFront integration)</a></p>'."\n";
505
+ echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp4-rtmp" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />Streams with the RTMP protocol, plus there is a full download fallback of the MP4 source file if streaming is not possible on a particular device.<br />This requires s2Member to be integrated with Amazon S3/CloudFront.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-s2stream-mp4-rtmp.x-php")).'</p>'."\n";
506
 
507
+ echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp4-rtmp-only\').toggle(); return false;" class="ws-dotted-link">JW Player (RTMP streaming MP4 only, via s2Member\'s Amazon S3/CloudFront integration)</a></p>'."\n";
508
+ echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp4-rtmp-only" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />Streams with the RTMP protocol only, with no access to the source file, only to the RTMP stream.<br />This requires s2Member to be integrated with Amazon S3/CloudFront.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-s2stream-mp4-rtmp-only.x-php")).'</p>'."\n";
509
 
510
  echo '<div class="ws-menu-page-hr"></div>'."\n";
511
 
512
  echo '<h3><code>[s2Stream /]</code> Audio Shortcode Examples (recommended — it\'s the easiest way)</h3>'."\n";
513
 
514
+ echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp3\').toggle(); return false;" class="ws-dotted-link">JW Player (MP3 file, via Rewrite URLs. Amazon S3/CloudFront NOT required)</a></p>'."\n";
515
+ echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp3" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />Works with any audio/video file. This does NOT require s2Member to be integrated with Amazon S3/CloudFront.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-s2stream-mp3.x-php")).'</p>'."\n";
516
 
517
+ echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp3-rtmp\').toggle(); return false;" class="ws-dotted-link">JW Player (RTMP streaming MP3, via s2Member\'s Amazon S3/CloudFront integration)</a></p>'."\n";
518
+ echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp3-rtmp" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />Streams with the RTMP protocol, plus there is a full download fallback of the MP3 source file if streaming is not possible on a particular device.<br />This requires s2Member to be integrated with Amazon S3/CloudFront.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-s2stream-mp3-rtmp.x-php")).'</p>'."\n";
519
 
520
+ echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp3-rtmp-only\').toggle(); return false;" class="ws-dotted-link">JW Player (RTMP streaming MP3 only, via s2Member\'s Amazon S3/CloudFront integration)</a></p>'."\n";
521
+ echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-s2stream-mp3-rtmp-only" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />Streams with the RTMP protocol only, with no access to the source file, only to the RTMP stream.<br />This requires s2Member to be integrated with Amazon S3/CloudFront.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-s2stream-mp3-rtmp-only.x-php")).'</p>'."\n";
522
 
523
  echo '<div class="ws-menu-page-hr"></div>'."\n";
524
 
525
+ echo '<h3>PHP Code Examples (for more advanced integrations via PHP — in WordPress themes)</h3>'."\n";
526
 
527
+ echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-standard-mp4\').toggle(); return false;" class="ws-dotted-link">JW Player (MP4 file, via Rewrite URLs. Amazon S3/CloudFront NOT required)</a></p>'."\n";
528
+ echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-standard-mp4" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This does NOT require s2Member to be integrated with Amazon S3/CloudFront.<br />Also see: <code>s2Member -› Download Options -› Advanced Mod Rewrite Linkage</code>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-standard-mp4.x-php")).'</p>'."\n";
529
 
530
+ echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-streaming-mp4\').toggle(); return false;" class="ws-dotted-link">JW Player (RTMP streaming MP4, via s2Member\'s Amazon S3/CloudFront integration)</a></p>'."\n";
531
+ echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-streaming-mp4" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This requires s2Member to be integrated with Amazon S3/CloudFront.<br />Also see: <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-summary/" target="_blank" rel="external">s2Member Codex -› API Functions</a>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-streaming-mp4.x-php")).'</p>'."\n";
532
 
533
+ echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-streaming-mp4-sca\').toggle(); return false;" class="ws-dotted-link">JW Player (RTMP streaming MP4, via s2Member\'s JSON/Shortcode alternative)</a></p>'."\n";
534
+ echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-streaming-mp4-sca" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This requires s2Member to be integrated with Amazon S3/CloudFront.<br />Also see: <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-summary/" target="_blank" rel="external">s2Member Codex -› API Functions</a>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-streaming-mp4-sca.x-php")).'</p>'."\n";
535
 
536
+ echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-streaming-mp4-webm\').toggle(); return false;" class="ws-dotted-link">JW Player (RTMP streaming MP4, advanced w/ multiple fallbacks)</a></p>'."\n";
537
+ echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-streaming-mp4-webm" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This requires s2Member to be integrated with Amazon S3/CloudFront.<br />Also see: <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-summary/" target="_blank" rel="external">s2Member Codex -› API Functions</a>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-streaming-mp4-webm.x-php")).'</p>'."\n";
538
 
539
  echo '</div>'."\n";
540
 
547
  {
548
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_before_rtmp_streaming", get_defined_vars());
549
 
550
+ echo '<div class="ws-menu-page-group" title="JW Player v5 &amp; RTMP Protocol Examples (Deprecated)">'."\n";
551
 
552
  echo '<div class="ws-menu-page-section ws-plugin--s2member-rtmp-streaming-section">'."\n";
553
+ echo '<h3>JW Player v5 &amp; RTMP Protocol Examples (Deprecated)</h3>'."\n";
554
  echo '<a href="http://www.longtailvideo.com/players/" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/jwplayer-logo.png" class="ws-menu-page-right" style="width:179px; height:58px; border:0;" alt="." /></a>'."\n";
555
+ echo '<p>While it is possible to serve audio/video files protected by s2Member, without needing to integrate Amazon S3 or CloudFront; we DO highly recommend that you integrate both Amazon S3 and Amazon CloudFront in order to maximize speed and compatibility across various viewing platforms. That being said, there are code samples below that will serve audio/video files both with and without Amazon S3/CloudFront. You can also check the <a href="'.esc_attr(c_ws_plugin__s2member_readmes::parse_readme_value("Forum URI")).'" target="_blank" rel="external">s2Member Support Forums</a> for tips/tricks if you like.</p>'."\n";
556
+ echo '<p><strong>One of the great things about Amazon CloudFront</strong>, is its ability to <strong>stream/seek media files</strong> in the truest sense of the word. For sites delivering protected <em>FLV/MP4/OGG/WEBM</em> and other streaming audio/video file types over the <em>RTMP</em> protocol, Amazon CloudFront is our recommendation. Once you\'ve successfully configured s2Member to use both Amazon S3 and Amazon CloudFront together, please review the code samples below. s2Member can automatically serve your protected files over the <em>RTMP</em> protocol using an Amazon CloudFront Streaming Distribution.</p>'."\n";
557
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_rtmp_streaming", get_defined_vars());
558
 
559
  echo '<div class="ws-menu-page-hr"></div>'."\n";
560
 
561
  echo '<h3>PHP Code Examples (for more advanced integrations)</h3>'."\n";
562
+ echo '<p>These examples exist from past versions of s2Member. JW Player v5 is now outdated by JW Player v6 (recommended).</p>'."\n";
563
 
564
+ echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-standard-mp4\').toggle(); return false;" class="ws-dotted-link">JW Player (MP4 file, via Rewrite URLs. Amazon S3/CloudFront NOT required)</a></p>'."\n";
565
+ echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-standard-mp4" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This does NOT require s2Member to be integrated with Amazon S3/CloudFront.<br />Also see: <code>s2Member -› Download Options -› Advanced Mod Rewrite Linkage</code>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-v5-standard-mp4.x-php")).'</p>'."\n";
566
 
567
+ echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-streaming-mp4\').toggle(); return false;" class="ws-dotted-link">JW Player (RTMP streaming MP4, via s2Member\'s Amazon S3/CloudFront integration)</a></p>'."\n";
568
+ echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-streaming-mp4" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This requires s2Member to be integrated with Amazon S3/CloudFront.<br />Also see: <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-summary/" target="_blank" rel="external">s2Member Codex -› API Functions</a>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-v5-streaming-mp4.x-php")).'</p>'."\n";
569
 
570
+ echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-streaming-mp4-sca\').toggle(); return false;" class="ws-dotted-link">JW Player (RTMP streaming MP4, via s2Member\'s JSON/Shortcode alternative)</a></p>'."\n";
571
+ echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-streaming-mp4-sca" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This requires s2Member to be integrated with Amazon S3/CloudFront.<br />Also see: <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-summary/" target="_blank" rel="external">s2Member Codex -› API Functions</a>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-v5-streaming-mp4-sca.x-php")).'</p>'."\n";
572
 
573
+ echo '<p style="font-size:110%;"><a href="#" onclick="jQuery(\'p#ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-streaming-mp4-webm\').toggle(); return false;" class="ws-dotted-link">JW Player (RTMP streaming MP4, advanced w/ multiple fallbacks)</a></p>'."\n";
574
+ echo '<p id="ws-plugin--s2member-rtmp-streaming-details-jwplayer-v5-streaming-mp4-webm" style="display:none;">Download <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">JW Player here</a>, and upload <code>/jwplayer/</code> to your website\'s root directory.<br />This requires s2Member to be integrated with Amazon S3/CloudFront.<br />Also see: <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-summary/" target="_blank" rel="external">s2Member Codex -› API Functions</a>.<br /><br />'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/jwplayer-v5-streaming-mp4-webm.x-php")).'</p>'."\n";
575
 
576
  echo '</div>'."\n";
577
 
596
  echo '<p>Or, if you really want to get advanced, you could do something like this:<br /><code>... /wp-content/plugins/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'<strong class="ws-menu-page-hilite">/s2member-file-inline-[yes|no]/s2member-file-download-key-[key]</strong>/example-file.zip</code><br /><code>... /wp-content/plugins/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'<strong class="ws-menu-page-hilite">/s2member-file-inline-yes/s2member-file-download-key-xS54df5ER4d5x</strong>/example-file.zip</code><br /><code>... /wp-content/plugins/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'<strong class="ws-menu-page-hilite">/s2member-file-inline-yes/s2member-skip-confirmation</strong>/example-file.zip</code></p>'."\n";
597
  echo '<p>Or even this, if you\'re using Remote Header Authorization:<br /><code>... /wp-content/plugins/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'<strong class="ws-menu-page-hilite">/s2member-file-remote</strong>/example-file.zip</code></p>'."\n";
598
  echo '<p>Specifying storage location option dynamically:<br /><code>... /wp-content/plugins/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'<strong class="ws-menu-page-hilite">/s2member-file-storage-[local|s3|cf]</strong>/example-file.zip</code><br /><code>... /wp-content/plugins/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'<strong class="ws-menu-page-hilite">/s2member-file-storage-cf</strong>/example-cloudfront-file.zip</code><br /><code>... /wp-content/plugins/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'<strong class="ws-menu-page-hilite">/s2member-file-storage-s3/s2member-file-inline</strong>/example-s3-file.html</code></p>'."\n";
599
+ echo '<p><em>* Note, the order of your s2Member-specific parameters with Advanced Mod-Rewrite Linkage is irrelevant. Feel free to add/remove, or even change the order. Everything discussed here is also Multisite compatible. Everything discussed here is also compatible when/if combined with Amazon S3/CDN Storage. However, NONE of this will work on servers that do NOT support <code>mod_rewrite</code>. Almost all web servers do though.</em></p>'."\n";
600
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_rewrite_linkage", get_defined_vars());
601
  echo '</div>'."\n";
602
 
613
 
614
  echo '<div class="ws-menu-page-section ws-plugin--s2member-shortcode-attrs-section">'."\n";
615
  echo '<h3>Shortcode Attributes &amp; API Functions (Explained In Full Detail)</h3>'."\n";
616
+ echo '<p>s2Member makes <a href="http://codex.wordpress.org/Shortcode_API#Overview" target="_blank" rel="external">Shortcodes</a> available to you, which allow you to generate File Download URLs and/or File Download Keys. Like most Shortcodes for WordPress, s2Member reads Attributes in your Shortcode. Many site owners like to know exactly how these Shortcode Attributes work. Below, is a brief overview of each possible Shortcode Attribute.</p>'."\n";
617
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_shortcode_attrs", get_defined_vars());
618
 
619
  echo '<div class="ws-menu-page-hr"></div>'."\n";
626
 
627
  echo '<td style="padding-top:0;">'."\n";
628
  echo '<ul>'."\n";
629
+ echo '<li><code>download="file.zip"</code> Location of the file, relative to the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory; or, relative to the root of your Amazon S3 Bucket, when applicable.</li>'."\n";
630
  echo '<li><code>download_key="no"</code> Defaults to <code>no</code>. If <code>download_key="1|on|yes|true|ip-forever|universal"</code>, s2Member will return a URL with an s2Member-generated File Download Key. You don\'t need to generate the File Download Key yourself, s2Member does it for you. If you set <code>download_key="ip-forever"</code>, the File Download Key that s2Member generates will last forever, for a specific IP Address; otherwise, by default, all File Download Keys expire after 24 hours automatically. If you set <code>download_key="universal"</code>, s2Member will generate a File Download Key that is good for anyone/everyone forever, with NO restrictions on who/where/when a file is accessed <em>(e.g. be careful with this one)</em>.</li>'."\n";
631
+ echo '<li><code>stream="no"</code> Defaults to <code>no</code> with <code>[s2File /]</code> Shortcode. Defaults to <code>yes</code> with <code>[s2Stream /]</code> Shortcode. If <code>stream="1|on|yes|true"</code>, s2Member will return a URL containing a parameter/directive, which forces the File Download to take place over the RTMP protocol if at all possible. This ONLY works when/if s2Member is configured to run with both Amazon S3/CloudFront. Please note however, it\'s better to use the example code provided in the section above, regarding: <code>JW Player and the RTMP Protocol</code>. Also note, if <code>get_streamer_json="1|on|yes|true"</code>, s2Member will automatically force <code>stream="yes"</code> for you.</li>'."\n";
632
+ echo '<li><code>inline=""</code> Defaults to <code>[empty]</code> with <code>[s2File /]</code> Shortcode. Defaults to <code>yes</code> with <code>[s2Stream /]</code> Shortcode. If <code>inline="1|on|yes|true"</code>, s2Member will serve the file inline, instead of as an actual File Download. If empty, s2Member will look at your <code>Inline File Extensions</code> configuration above, and serve the file inline; if, and only if, its extension matches one found in your configuration. By default, s2Member serves all files as attachments <em>(i.e. downloads)</em>, except in the case of the <code>[s2Stream /]</code> Shortcode where this defaults to <code>yes</code>. Please read the section above regarding <code>Inline File Extensions</code> for further details. Also note, this Shortcode Attribute does NOTHING for files served via Amazon CloudFront. See the tech-notes listed in the Amazon CloudFront section for further details and workarounds.</li>'."\n";
633
+ echo '<li><code>storage=""</code> Defaults to <code>[empty]</code>. If <code>storage="local|s3|cf"</code>, s2Member will serve the file from a specific source location, based on the value of this Shortcode Attribute. For example, if you\'ve configured Amazon S3 and/or CloudFront; but, there are a few files that you want to upload locally to the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory; you can force s2Member to serve a file from local storage by setting <code>storage="local"</code> explicitly.</li>'."\n";
634
  echo '<li><code>remote="no"</code> Defaults to <code>no</code>. If <code>remote="1|on|yes|true"</code>, s2Member will authenticate access to the File Download via Remote Header Authorization, instead of through your web site. This is similar to <code>.htaccess</code> protection routines of yester-year</code>. Please check the <code>Remote Authorization and Podcasting</code> section for further details about how this works.</li>'."\n";
635
  echo '<li><code>ssl=""</code> Defaults to <code>[empty]</code>. If <code>ssl="1|on|yes|true"</code>, s2Member will generate a File Download URL with an SSL protocol <em>(i.e. the URL will start with <code>https://</code> or <code>rtmpe://</code>)</em>. If empty, s2Member will only generate a File Download URL with an SSL protocol, when/if the Post/Page/URL firing the Shortcode itself, is also being viewed over SSL. Otherwise, s2Member will use a non-SSL protocol by default.</li>'."\n";
636
+ echo '<li><code>rewrite="no"</code> Defaults to <code>no</code> with <code>[s2File /]</code> Shortcode. Defaults to <code>yes</code> with <code>[s2Stream /]</code> Shortcode. If <code>rewrite="1|on|yes|true"</code>, s2Member will generate a File Download URL that takes full advantage of s2Member\'s Advanced Mod Rewrite functionality. If you\'re running an Apache web server, or another server that supports <code>mod_rewrite</code>, we highly recommend turning this on. s2Member\'s <code>mod_rewrite</code> URLs do NOT contain query string parameters, making them more portable/compatible with other software applications and/or plugins for WordPress. If you\'re integrating with JW Player, you MUST use <code>rewrite="yes"</code>.</li>'."\n";
637
+ echo '<li><code>rewrite_base=""</code> Defaults to <code>[empty]</code>. If <code>rewrite_base="'.esc_attr(site_url("/")).'"</code>, s2Member will generate a File Download URL that takes full advantage of s2Member\'s Advanced Mod Rewrite functionality, and it will use the rewrite base URL as a prefix. This could be useful on some WordPress installations that use advanced directory structures. It could also be useful for site owners using virtual directories that point to <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code>. Note, if <code>rewrite_base</code> is set, s2Member will automatically force <code>rewrite="yes"</code> for you.</li>'."\n";
638
  echo '<li><code>skip_confirmation="no"</code> Defaults to <code>no</code>. If <code>skip_confirmation="1|on|yes|true"</code>, s2Member will generate a File Download URL which contains a directive, telling s2Member NOT to introduce any JavaScript confirmation prompts on your site, for this File Download URL. Please note, s2Member will automatically detect links, anywhere in your content, and/or anywhere in your theme files, that contain <code>s2member_file_download</code> or <code>s2member-files</code>. Whenever a logged-in Member clicks a link that contains <code>s2member_file_download</code> or <code>s2member-files</code>, the system will politely ask the User to confirm the download using a very intuitive JavaScript confirmation prompt, which contains specific details about your configured download limitations. This way your Members will be aware of how many files they\'ve downloaded in the current period; and they\'ll be able to make a conscious decision about whether to proceed with a specific download or not.</li>'."\n";
639
+ echo '<li><code>url_to_storage_source="no"</code> Defaults to <code>no</code> with <code>[s2File /]</code> Shortcode. Defaults to <code>yes</code> with <code>[s2Stream /]</code> Shortcode. If <code>url_to_storage_source="1|on|yes|true"</code>, s2Member will generate a File Download URL which points directly to the storage source. This is only functional with Amazon S3 and/or CloudFront integrations. If you create a URL that points directly to the storage source <em>(i.e. points directly to Amazon S3 or CloudFront)</em>, s2Member will NOT be able to further authenticate the current User/Member; and, s2Member will NOT be able to count the File Download against the current User\'s account record, because the URL being generated does not pass back through s2Member at all, it points directly to the storage source. For this reason, if you set <code>url_to_storage_source="true"</code>, you should also set <code>check_user="true"</code> and <code>count_against_user="true"</code>, telling s2Member to authenticate the current User, and if authenticated, count this File Download URL against the current User\'s account record in real-time <em>(i.e. as the URL is being generated) </em>, while it still has a chance to do so. This Shortcode Attribute is useful when you stream files over the RTMP protocol; where an <code>http://</code> URL is not feasible. It also helps in situations where a 3rd-party software application will not work as intended, with s2Member\'s internal redirection to Amazon S3/CloudFront files. Important, when <code>check_user="true"</code> and/or <code>count_against_user="true"</code>, the Shortcode will return an empty and/or null object value in situations where the current User/Member does NOT have access to the file.</li>'."\n";
640
  echo '<li><code>count_against_user="no"</code> Defaults to <code>no</code> with <code>[s2File /]</code> Shortcode. Defaults to <code>yes</code> with <code>[s2Stream /]</code> Shortcode. If <code>count_against_user="1|on|yes|true"</code>, it will automatically force <code>check_user="true"</code> as well. In other words, s2Member will authenticate the current User, and if authenticated, count this File Download URL against the current User\'s account record in real-time <em>(i.e. as the URL is being generated) </em>. This is off by default with the <code>[s2File /]</code> Shortcode. By default, s2Member will simply generate a File Download URL, and upon a User/Member clicking the URL, s2Member will authenticate the User/Member at that time, count the File Download against their account record, and serve the File Download. In other words, under normal circumstances, there is no reason to set <code>check_user="true"</code> and/or <code>count_against_user="true"</code> when generating the URL itself. However, this is a useful Shortcode Attribute when <code>url_to_storage_source="true"</code>. Please note, when <code>check_user="true"</code> and/or <code>count_against_user="true"</code>, the Shortcode will return an empty and/or null object value in situations where the current User/Member does NOT have access to the file.</li>'."\n";
641
  echo '<li><code>check_user="no"</code> Defaults to <code>no</code> with <code>[s2File /]</code> Shortcode. Defaults to <code>yes</code> with <code>[s2Stream /]</code> Shortcode. If <code>check_user="1|on|yes|true"</code>, s2Member will authenticate the current User before allowing the File Download URL to be generated. This is off by default with the <code>[s2File /]</code> Shortcode. By default, s2Member will simply generate a File Download URL, and upon a User/Member clicking the URL, s2Member will authenticate the User/Member at that time, and serve the File Download to the User/Member. In other words, under normal circumstances, there is no reason to set <code>check_user="true"</code> and/or <code>count_against_user="true"</code> when generating the URL itself. However, this IS a useful Shortcode Attribute when <code>url_to_storage_source="true"</code>. Please note, when <code>check_user="true"</code> and/or <code>count_against_user="true"</code>, the Shortcode will return an empty and/or null object value in situations where the current User/Member does NOT have access to the file.</li>'."\n";
642
+ echo '<li><code>get_streamer_json="no"</code> Defaults to <code>no</code>. N/A with <code>[s2Stream /]</code> Shortcode. If <code>get_streamer_json="1|on|yes|true"</code>, the <code>[s2File /]</code> Shortcode will return a JSON object for JavaScript notation, making it possible to integrate the <code>[s2File /]</code> Shortcode into JavaScript routines that configure streaming media players. For further details, please review the section above: <code>JW Player &amp; RTMP Protocol Examples</code>. Note, if you set <code>get_streamer_json="true"</code>, s2Member will automatically force <code>url_to_storage_source="true"</code> and <code>stream="true"</code>. For that reason, you should carefully review the details and warning above regarding <code>url_to_storage_source</code>. If you set <code>get_streamer_json="true"</code>, you should also set <code>check_user="true"</code> and <code>count_against_user="true"</code>.</li>'."\n";
643
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_shortcode_attrs_s2file_lis", get_defined_vars());
644
  echo '</ul>'."\n";
645
  echo '</td>'."\n";
651
  echo '<div class="ws-menu-page-hr"></div>'."\n";
652
 
653
  echo '<h4 style="margin:0;">Additional <code>[s2Stream /]</code> Shortcode Attributes:</h4>'."\n";
654
+ echo '<p style="margin:0;"><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/jwplayer-s2stream-shortcodes/" target="_blank" rel="external">JW Player w/ <code>[s2Stream /]</code> Shortcodes</a>.</p>'."\n";
655
  echo '<p style="margin:0;"><strong>See also:</strong> API Function <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-functions/#src_doc_s2member_file_download_url()" target="_blank" rel="external">s2member_file_download_url()</a> for PHP integration.</p>'."\n";
656
  echo '<table class="form-table" style="margin-top:0;">'."\n";
657
  echo '<tbody>'."\n";
659
 
660
  echo '<td style="padding-top:0;">'."\n";
661
  echo '<ul>'."\n";
662
+ echo '<li><code>file_download="video.mp4"</code> Location of the audio/video file, relative to the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory; or, relative to the root of your Amazon S3 Bucket, when applicable.</li>'."\n";
663
+ echo '<li><code>player="jwplayer-v6-rtmp"</code> Required. Current supported players in this Shortcode include: <code>jwplayer-v6</code> (works with any audio/video file, and you do NOT need to have Amazon S3 or CloudFront integrated for this to work), <code>jwplayer-v6-rtmp</code> (streams with the RTMP protocol, plus there is a full download fallback of the source file if streaming is not possible on a particular device; this requires both Amazon S3 and CloudFront integration), <code>jwplayer-v6-rtmp-only</code> (streams with the RTMP protocol only, with no access to the source file, only to the RTMP stream; this requires both Amazon S3 and CloudFront integration).</li>'."\n";
664
+ echo '<li><code>player_id=""</code> Optional. HTML div ID for the audio/video player. Defaults to a unique ID generated by s2Member for each instance of your Shortcode.</li>'."\n";
665
  echo '<li><code>player_path="/jwplayer/jwplayer.js"</code> Required. Path to the player\'s JavaScript file (ex: <code>/jwplayer/jwplayer.js</code> — you should upload the <a href="http://www.longtailvideo.com/players/" target="_blank" rel="external">/jwplayer</a> folder to the root of your web directory).</li>'."\n";
666
+ echo '<li><code>player_{setting}=""</code> Optional. Any additional configuration attributes supported by your audio/video player, prefixed with <code>player_</code>. For JW Player v6, see <a href="http://www.longtailvideo.com/support/jw-player/28839/embedding-the-player" target="_blank" rel="external">this article please</a>. Examples: <code>player_width="480"</code>, <code>player_height="270"</code>, <code>player_title="My Video"</code>, <code>player_description="A video about something."</code>, <code>player_image="http://www.example.com/wp-content/uploads/video-preview.jpg"</code>, <code>player_mediaid="video_ei0wsx23"</code>, <code>player_autostart="true"</code>, <code>player_skin="/jwplayer/my-skin.xml"</code>, <code>player_key="my-license-key"</code>, <code>player_captions="{file:\'/assets/captions-en.vtt\',label:\'English\'}"</code> (<em>With <a href="http://www.longtailvideo.com/support/jw-player/28845/adding-video-captions" target="_blank" rel="external">Captions</a>, you can exclude the square array brackets to avoid Shortcode parsing issues. s2Member will automatically wrap your Caption objects with square array brackets.</em>). Please note that "Advanced Options Blocks" listed on <a href="http://www.longtailvideo.com/support/jw-player/28839/embedding-the-player" target="_blank" rel="external">this page</a> are NOT supported here. For those, please use: <code>player_option_blocks=""</code> (see below).</li>'."\n";
667
+ echo '<li><code>player_option_blocks=""</code> Optional. Any "Advanced Option Blocks" supported by your audio/video player. For JW Player v6, see <a href="http://www.longtailvideo.com/support/jw-player/28839/embedding-the-player" target="_blank" rel="external">this article please</a>. Here are some examples: <code>player_option_blocks="sharing:{}"</code>, <code>player_option_blocks="sharing:{}, logo: {file: \'/logo.png\', link: \'http://example.com\'}"</code>. Or: <code>player_option_blocks="c2hhcmluZzoge30="</code> (base64 encoded version of <code>sharing:{}</code>). Please note that "Advanced Options Blocks" can be defined in plain text or with a <a href="http://www.base64encode.org/" target="_blank" rel="external">base64 encoded string</a>. Advanced Option Blocks are JavaScript objects with properties. If you have trouble defining JavaScript object properties inside a Shortcode Attribute, please use <a href="http://www.base64encode.org/" target="_blank" rel="external">this tool</a> to base64 encode your Advanced Option Blocks, so that you end up with a string that\'s compatible with Shortcode Attributes.</li>'."\n";
668
  echo '<li>Please check the <strong>Shortcode Attributes</strong> Tab in <a href="http://www.s2member.com/kb/jwplayer-s2stream-shortcodes/#using-s2stream-shortcodes" target="_blank" rel="external">this KB article</a> for further details on everything here.</li>'."\n";
669
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_shortcode_attrs_s2stream_lis", get_defined_vars());
670
  echo '</ul>'."\n";
684
 
685
  echo '<td style="padding-top:0;">'."\n";
686
  echo '<ul>'."\n";
687
+ echo '<li><code>file_download="file.zip"</code> Location of the file, relative to the <code>/'.esc_html(c_ws_plugin__s2member_utils_dirs::basename_dir_app_data($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])).'/</code> directory; or, relative to the root of your Amazon S3 Bucket, when applicable.</li>'."\n";
688
  echo '<li><code>directive=""</code> Defaults to <code>[empty]</code>. If <code>directive="ip-forever|universal"</code>, s2Member will return a special File Download Key. If you set <code>directive="ip-forever"</code>, the File Download Key that s2Member generates will last forever, for a specific IP Address; otherwise, by default, all File Download Keys expire after 24 hours automatically. If you set <code>directive="universal"</code>, s2Member will generate a File Download Key that is good for anyone/everyone forever, with NO restrictions on who/where/when a file is accessed <em>(e.g. be careful with this one)</em>.</li>'."\n";
689
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_shortcode_attrs_s2key_lis", get_defined_vars());
690
  echo '</ul>'."\n";
708
 
709
  echo '<div class="ws-menu-page-section ws-plugin--s2member-gzip-conflicts-section">'."\n";
710
  echo '<h3>Preventing GZIP Conflicts On Server (Instructions)</h3>'."\n";
711
+ echo '<p>Protected files served by s2Member through PHP scripts, are already compressed. Therefore, <a href="http://code.google.com/speed/articles/gzip.html" target="_blank" rel="nofollow external xlink">GZIP compression</a> is not needed during protected file delivery. Some web servers (i.e. Apache, LiteSpeed, and similar) include GZIP compression rules through server-side extensions, like <code>mod_deflate</code> for example. While s2Member encourages the use of extensions like <code>mod_deflate</code>, it is best to disable GZIP automatically (i.e. temporarily) during s2Member\'s delivery of a protected file through a PHP script. This avoids conflicts on the server which might otherwise lead to corrupted file downloads. s2Member makes a valiant effort to accomplish this via PHP, all on its own. However, it never hurts to add this section of code to the root <code>.htaccess</code> file for your WordPress installation. Optional, but highly recommended.</p>'."\n";
712
  do_action("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_gzip_conflicts", get_defined_vars());
713
 
714
  echo '<div class="ws-menu-page-hr"></div>'."\n";
715
+ echo '<p style="margin:0; font-weight:bold;">s2Member automatically adds this to your <code>.htaccess</code> file upon activation of the plugin.</p>'."\n";
716
  echo '<p style="margin:0;">The following <code>mod_rewrite</code> rule goes inside this file: <code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path(ABSPATH.".htaccess")).'</code></p>'."\n";
717
  echo '<pre><code>'.esc_html(trim(c_ws_plugin__s2member_utilities::evl(file_get_contents($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_no_gzip_htaccess"])))).'</code></pre>';
718
+ echo '<p><strong>* Tip:</strong> this covers all types of integration with s2Member File Downloads, even if you\'re using s2Member\'s Advanced Mod Rewrite Linkage.</p>'."\n";
719
  echo '</div>'."\n";
720
 
721
  echo '</div>'."\n";
731
 
732
  echo '<div class="ws-menu-page-section ws-plugin--s2member-custom-capability-files-section">' . "\n";
733
  echo '<h3>Restricting Files, Based On Custom Capabilities</h3>' . "\n";
734
+ echo '<p>If you\'re NOT familiar with Custom Capabilities yet, please read: <code>Dashboard -› s2Member -› API Scripting -› Custom Capability Packages</code>. Once you understand the basic concept of Custom Capabilities &amp; Protected File Downloads, you\'ll see that (by default) s2Member does NOT handle File Download Protection with respect to Custom Capabilities. That\'s where Custom Capability Sub-directories come in.</p>' . "\n";
735
  echo '<p>You can create Custom Capability Sub-directories under: <code>' . esc_html (c_ws_plugin__s2member_utils_dirs::doc_root_path ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])) . '</code>. For instance, if you have a Custom Capability <code>music</code>, you can place protected files that should ONLY be accessible to Members with <code>access_s2member_ccap_music</code>, inside: <code>/' . esc_html (c_ws_plugin__s2member_utils_dirs::basename_dir_app_data ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])) . '/access-s2member-ccap-music/</code>. Some examples are provided below.</p>' . "\n";
736
  do_action ("ws_plugin__s2member_during_down_ops_page_during_left_sections_during_custom_capability_files", get_defined_vars ());
737
 
includes/menu-pages/els-ops.inc.php CHANGED
@@ -32,7 +32,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_els_ops"))
32
  echo '<div class="wrap ws-menu-page">'."\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>'."\n";
35
- echo '<h2>s2Member® API / List Servers</h2>'."\n";
36
 
37
  echo '<table class="ws-menu-page-table">'."\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">'."\n";
@@ -48,13 +48,13 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_els_ops"))
48
  {
49
  do_action("ws_plugin__s2member_during_els_ops_page_during_left_sections_before_mailchimp", get_defined_vars());
50
 
51
- echo '<div class="ws-menu-page-group" title="MailChimp® Integration">'."\n";
52
 
53
  echo '<div class="ws-menu-page-section ws-plugin--s2member-mailchimp-section">'."\n";
54
  echo '<a href="http://www.s2member.com/mailchimp" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/mailchimp-stamp.png" class="ws-menu-page-right" style="width:125px; height:125px; border:0;" alt="." /></a>'."\n";
55
- echo '<h3>MailChimp® List Server Integration (optional)</h3>'."\n";
56
- echo '<p>s2Member can be integrated with MailChimp®. MailChimp® is an email marketing service. MailChimp® makes it easy to send email newsletters to your Customers, manage your MailChimp® subscriber lists, and track campaign performance. Although s2Member can be integrated with almost ANY list server, we highly recommend MailChimp®; because of their <a href="http://www.s2member.com/mailchimp-api-docs" target="_blank" rel="external">powerful API for MailChimp® services</a>. In future versions of s2Member, we plan to build additional features into s2Member that work with, and extend, MailChimp® services.</p>'."\n";
57
- echo '<p>For now, we\'ve covered the basics. You can have your Members automatically subscribed to your MailChimp® marketing lists <em>(e.g. newsletters / auto-responders)</em>. You\'ll need a <a href="http://www.s2member.com/mailchimp" target="_blank" rel="external">MailChimp® account</a>, a <a href="http://www.s2member.com/mailchimp-api-key" target="_blank" rel="external">MailChimp® API Key</a>, and your <a href="#" onclick="alert(\'To obtain your MailChimp® List ID(s), log into your MailChimp® account and click the Lists tab. Now click the (View) button, for the List(s) you want to integrate with s2Member. Then, click the (Settings) link. At the bottom of the (Settings) page, for each list; you\\\'ll find a Unique List ID.\'); return false;">MailChimp® List IDs</a>.</p>'."\n";
58
  do_action("ws_plugin__s2member_during_els_ops_page_during_left_sections_during_mailchimp", get_defined_vars());
59
 
60
  echo '<table class="form-table">'."\n";
@@ -63,7 +63,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_els_ops"))
63
 
64
  echo '<th>'."\n";
65
  echo '<label for="ws-plugin--s2member-mailchimp-api-key">'."\n";
66
- echo 'MailChimp® API Key:'."\n";
67
  echo '</label>'."\n";
68
  echo '</th>'."\n";
69
 
@@ -72,7 +72,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_els_ops"))
72
 
73
  echo '<td>'."\n";
74
  echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_mailchimp_api_key" id="ws-plugin--s2member-mailchimp-api-key" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["mailchimp_api_key"]).'" /><br />'."\n";
75
- echo 'Once you have a MailChimp® account, you\'ll need to <a href="http://www.s2member.com/mailchimp-api-key" target="_blank" rel="external">add an API Key</a>.'."\n";
76
  echo '</td>'."\n";
77
 
78
  echo '</tr>'."\n";
@@ -102,14 +102,14 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_els_ops"))
102
 
103
  echo '</tbody>'."\n";
104
  echo '</table>'."\n";
105
-
106
  echo '<div class="ws-menu-page-hr"></div>'."\n";
107
-
108
  echo '<div class="ws-menu-page-hilite" style="border-radius:3px; padding:5px;">'."\n";
109
- echo '<p style="font-size:110%; margin-top:0;"><span>We HIGHLY recommend that you enable logging during your initial testing phase. Logs produce lots of useful details that can help in debugging. Logs can help you find issues in your configuration and/or problems during MailChimp® processing. See: <a href="'.esc_attr(admin_url("/admin.php?page=ws-plugin--s2member-logs")).'">Log Files (Debug)</a>.</span></p>'."\n";
110
  echo '<p style="font-size:110%; margin-bottom:0;"><span class="ws-menu-page-error">However, it is VERY IMPORTANT to disable logging once you go live. Log files may contain personally identifiable information, credit card numbers, secret API credentials, passwords and/or other sensitive information. We STRONGLY suggest that logging be disabled on a live site (for security reasons).</span></p>'."\n";
111
  echo '</div>'."\n";
112
-
113
  echo '</div>'."\n";
114
 
115
  echo '</div>'."\n";
@@ -121,15 +121,15 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_els_ops"))
121
  {
122
  do_action("ws_plugin__s2member_during_els_ops_page_during_left_sections_before_aweber", get_defined_vars());
123
 
124
- echo '<div class="ws-menu-page-group" title="AWeber® Integration">'."\n";
125
 
126
  echo '<div class="ws-menu-page-section ws-plugin--s2member-aweber-section">'."\n";
127
  echo '<a href="http://www.s2member.com/aweber" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/aweber-logo.png" class="ws-menu-page-right" style="width:125px; height:125px; border:0;" alt="." /></a>'."\n";
128
- echo '<h3>AWeber® List Server Integration (optional)</h3>'."\n";
129
- echo '<p>s2Member can be integrated with AWeber®. AWeber® is an email marketing service. Whether you\'re looking to get your first email campaign off the ground, or you\'re a seasoned veteran who wants to dig into advanced tools like detailed email web analytics, activity based segmentation, geo-targeting and broadcast split-testing, AWeber\'s got just what you need to make email marketing work for you.</p>'."\n";
130
- echo '<p>You can have your Members automatically subscribed to your AWeber® marketing lists <em>(e.g. newsletters / auto-responders)</em>. You\'ll need an <a href="http://www.s2member.com/aweber" target="_blank" rel="external">AWeber® account</a> and your <a href="#" onclick="alert(\'To obtain your AWeber® List ID(s), log into your AWeber® account. Click on the Lists tab. On that page you\\\'ll find a Unique List ID associated with each of your lists. AWeber® sometimes refers to this as a List Name instead of a List ID.\'); return false;">AWeber® List IDs</a>. You will ALSO need to configure a <a href="http://www.s2member.com/kb/aweber-email-parser-for-s2member/" target="_blank" rel="external">Custom Email Parser</a> inside your AWeber® account.</p>'."\n";
131
- echo '<p>Log into AWeber®, and go to <em>My Lists -› Email Parser</em>. If you like, choose the PayPal® Parser <em>(even if you\'re not using PayPal® as your Payment Gateway)</em>. You can safely ignore the additional instructions they provide. s2Member just needs the PayPal® box checked, and that\'s all. Or, even better, integrate <a href="http://www.s2member.com/kb/aweber-email-parser-for-s2member/" target="_blank" rel="external">s2Member\'s Custom Email Parser</a> for AWeber, which <strong>will improve reliability</strong> and flexibility.</p>'."\n";
132
- echo '<p><em><strong>AWeber® Tip:</strong> If you want your Members to be subscribed to multiple AWeber® List IDs at the same time, instead of comma-delimiting those List IDs here; we suggest a single List ID in your s2Member® integration; then use <a href="https://help.aweber.com/entries/21696463-Can-I-Add-Subscribers-to-More-Than-One-List-At-Once-" target="_blank" rel="external">AWeber® Automation Rules</a> for this. Automation Rules can also reduce the number of email confirmation notices that Members receive.</em></p>'."\n";
133
  do_action("ws_plugin__s2member_during_els_ops_page_during_left_sections_during_aweber", get_defined_vars());
134
 
135
  echo '<table class="form-table">'."\n";
@@ -159,14 +159,14 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_els_ops"))
159
 
160
  echo '</tbody>'."\n";
161
  echo '</table>'."\n";
162
-
163
  echo '<div class="ws-menu-page-hr"></div>'."\n";
164
-
165
  echo '<div class="ws-menu-page-hilite" style="border-radius:3px; padding:5px;">'."\n";
166
- echo '<p style="font-size:110%; margin-top:0;"><span>We HIGHLY recommend that you enable logging during your initial testing phase. Logs produce lots of useful details that can help in debugging. Logs can help you find issues in your configuration and/or problems during AWeber® processing. See: <a href="'.esc_attr(admin_url("/admin.php?page=ws-plugin--s2member-logs")).'">Log Files (Debug)</a>.</span></p>'."\n";
167
  echo '<p style="font-size:110%; margin-bottom:0;"><span class="ws-menu-page-error">However, it is VERY IMPORTANT to disable logging once you go live. Log files may contain personally identifiable information, credit card numbers, secret API credentials, passwords and/or other sensitive information. We STRONGLY suggest that logging be disabled on a live site (for security reasons).</span></p>'."\n";
168
  echo '</div>'."\n";
169
-
170
  echo '</div>'."\n";
171
 
172
  echo '</div>'."\n";
@@ -243,7 +243,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_els_ops"))
243
  echo '<div class="ws-menu-page-section ws-plugin--s2member-opt-out-section">'."\n";
244
  echo '<h3>Automate Un-Subscribe/Opt-Out Removals (optional)</h3>'."\n";
245
  echo '<p>s2Member can automatically <em>(and silently)</em> remove Users/Members from the List Servers you\'ve configured above. s2Member is also capable of automating this, based on your own personal configuration preferences. Below, you can choose which Events you consider grounds for List Removal. It is also important to point out that s2Member will ONLY remove Users/Members from the Lists you\'ve configured at the Level the User/Member is or was at during the time of the Event. For example, if a Level #1 Member is deleted, they will ONLY be removed from the List(s) you\'ve configured at Level #1. If an account is upgraded from Level #1 to Level #2, they will ONLY be removed from the List(s) you\'ve configured at Level #1. Of course, all of this is based on the configuration below.</p>'."\n";
246
- echo '<p><em><strong>*Regarding AWeber®*</strong> these will NOT work for AWeber® until you <a href="http://www.s2member.com/aweber-notification-email" target="_blank" rel="external">add a Notification Email</a> to your AWeber® account matching the "EMail From Address" configured in <code>s2Member -› General Options -› EMail Configuration</code>. Which is currently set to: <code>'.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"]).'</code>. This is a required step if you want s2Member to be authenticated when it emails List Removal requests to AWeber®.</em></p>'."\n";
247
  do_action("ws_plugin__s2member_during_els_ops_page_during_left_sections_during_opt_out", get_defined_vars());
248
 
249
  echo '<table class="form-table">'."\n";
@@ -287,7 +287,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_els_ops"))
287
  echo '</select><br />'."\n";
288
  echo '<em><strong>*Transitions*</strong> When/if s2Member automatically removes a Member from Lists at their current Level# (based on your configuration in the previous section), this setting tells s2Member that it should <strong>also</strong> transition the Member to any Lists you\'ve configured at the new Access Level# (i.e. Role) they are being changed to. For example, if a Member is demoted from Level #1 to Level #0, do you want s2Member to add them to the Level #0 List(s) after it removes them from the Level #1 List(s)?</em><br /><br />'."\n";
289
  echo '<em><strong>*If removed from a previous list, or NOT?*</strong> You can choose your preference above. When/if s2Member automatically transitions a mailing list subscriber, it will first try to remove the subscriber from a previous mailing list. If s2Member is able to remove the subscriber from a previous list before the transition takes place, s2Member will then make an attempt (based on your configuration) to transition the subscriber to a new/different list silently (e.g. without a new confirmation email being sent out). If s2Member is NOT able to remove a subscriber from a previous list, it can - (if configured to do so), still transition a subscriber to a new list, by sending the subscriber a new email confirmation letter (e.g. this is NOT silent, because you absolutely NEED the subscriber\'s permission in this case).</em><br /><br />'."\n";
290
- echo '<em><strong>*Seamless with MailChimp®*</strong> If enabled, Automatic List Transitions work seamlessly with MailChimp®. Automatic List Transitions also work with AWeber®, but AWeber® will ALWAYS send the User/Member a new confirmation email, asking them to confirm changes to their mailing list subscription with you. Work is underway to improve this aspect of s2Member\'s integration with AWeber® in a future release. Ideally, a Customer would be transitioned silently behind the scene with AWeber® too, when appropriate.</em>'."\n";
291
  echo '</td>'."\n";
292
 
293
  echo '</tr>'."\n";
32
  echo '<div class="wrap ws-menu-page">'."\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>'."\n";
35
+ echo '<h2>s2Member API / List Servers</h2>'."\n";
36
 
37
  echo '<table class="ws-menu-page-table">'."\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">'."\n";
48
  {
49
  do_action("ws_plugin__s2member_during_els_ops_page_during_left_sections_before_mailchimp", get_defined_vars());
50
 
51
+ echo '<div class="ws-menu-page-group" title="MailChimp Integration">'."\n";
52
 
53
  echo '<div class="ws-menu-page-section ws-plugin--s2member-mailchimp-section">'."\n";
54
  echo '<a href="http://www.s2member.com/mailchimp" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/mailchimp-stamp.png" class="ws-menu-page-right" style="width:125px; height:125px; border:0;" alt="." /></a>'."\n";
55
+ echo '<h3>MailChimp List Server Integration (optional)</h3>'."\n";
56
+ echo '<p>s2Member can be integrated with MailChimp. MailChimp is an email marketing service. MailChimp makes it easy to send email newsletters to your Customers, manage your MailChimp subscriber lists, and track campaign performance. Although s2Member can be integrated with almost ANY list server, we highly recommend MailChimp; because of their <a href="http://www.s2member.com/mailchimp-api-docs" target="_blank" rel="external">powerful API for MailChimp services</a>. In future versions of s2Member, we plan to build additional features into s2Member that work with, and extend, MailChimp services.</p>'."\n";
57
+ echo '<p>For now, we\'ve covered the basics. You can have your Members automatically subscribed to your MailChimp marketing lists <em>(e.g. newsletters / auto-responders)</em>. You\'ll need a <a href="http://www.s2member.com/mailchimp" target="_blank" rel="external">MailChimp account</a>, a <a href="http://www.s2member.com/mailchimp-api-key" target="_blank" rel="external">MailChimp API Key</a>, and your <a href="#" onclick="alert(\'To obtain your MailChimp List ID(s), log into your MailChimp account and click the Lists tab. Now click the (View) button, for the List(s) you want to integrate with s2Member. Then, click the (Settings) link. At the bottom of the (Settings) page, for each list; you\\\'ll find a Unique List ID.\'); return false;">MailChimp List IDs</a>.</p>'."\n";
58
  do_action("ws_plugin__s2member_during_els_ops_page_during_left_sections_during_mailchimp", get_defined_vars());
59
 
60
  echo '<table class="form-table">'."\n";
63
 
64
  echo '<th>'."\n";
65
  echo '<label for="ws-plugin--s2member-mailchimp-api-key">'."\n";
66
+ echo 'MailChimp API Key:'."\n";
67
  echo '</label>'."\n";
68
  echo '</th>'."\n";
69
 
72
 
73
  echo '<td>'."\n";
74
  echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_mailchimp_api_key" id="ws-plugin--s2member-mailchimp-api-key" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["mailchimp_api_key"]).'" /><br />'."\n";
75
+ echo 'Once you have a MailChimp account, you\'ll need to <a href="http://www.s2member.com/mailchimp-api-key" target="_blank" rel="external">add an API Key</a>.'."\n";
76
  echo '</td>'."\n";
77
 
78
  echo '</tr>'."\n";
102
 
103
  echo '</tbody>'."\n";
104
  echo '</table>'."\n";
105
+
106
  echo '<div class="ws-menu-page-hr"></div>'."\n";
107
+
108
  echo '<div class="ws-menu-page-hilite" style="border-radius:3px; padding:5px;">'."\n";
109
+ echo '<p style="font-size:110%; margin-top:0;"><span>We HIGHLY recommend that you enable logging during your initial testing phase. Logs produce lots of useful details that can help in debugging. Logs can help you find issues in your configuration and/or problems during MailChimp processing. See: <a href="'.esc_attr(admin_url("/admin.php?page=ws-plugin--s2member-logs")).'">Log Files (Debug)</a>.</span></p>'."\n";
110
  echo '<p style="font-size:110%; margin-bottom:0;"><span class="ws-menu-page-error">However, it is VERY IMPORTANT to disable logging once you go live. Log files may contain personally identifiable information, credit card numbers, secret API credentials, passwords and/or other sensitive information. We STRONGLY suggest that logging be disabled on a live site (for security reasons).</span></p>'."\n";
111
  echo '</div>'."\n";
112
+
113
  echo '</div>'."\n";
114
 
115
  echo '</div>'."\n";
121
  {
122
  do_action("ws_plugin__s2member_during_els_ops_page_during_left_sections_before_aweber", get_defined_vars());
123
 
124
+ echo '<div class="ws-menu-page-group" title="AWeber Integration">'."\n";
125
 
126
  echo '<div class="ws-menu-page-section ws-plugin--s2member-aweber-section">'."\n";
127
  echo '<a href="http://www.s2member.com/aweber" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/aweber-logo.png" class="ws-menu-page-right" style="width:125px; height:125px; border:0;" alt="." /></a>'."\n";
128
+ echo '<h3>AWeber List Server Integration (optional)</h3>'."\n";
129
+ echo '<p>s2Member can be integrated with AWeber. AWeber is an email marketing service. Whether you\'re looking to get your first email campaign off the ground, or you\'re a seasoned veteran who wants to dig into advanced tools like detailed email web analytics, activity based segmentation, geo-targeting and broadcast split-testing, AWeber\'s got just what you need to make email marketing work for you.</p>'."\n";
130
+ echo '<p>You can have your Members automatically subscribed to your AWeber marketing lists <em>(e.g. newsletters / auto-responders)</em>. You\'ll need an <a href="http://www.s2member.com/aweber" target="_blank" rel="external">AWeber account</a> and your <a href="#" onclick="alert(\'To obtain your AWeber List ID(s), log into your AWeber account. Click on the Lists tab. On that page you\\\'ll find a Unique List ID associated with each of your lists. AWeber sometimes refers to this as a List Name instead of a List ID.\'); return false;">AWeber List IDs</a>. You will ALSO need to configure a <a href="http://www.s2member.com/kb/aweber-email-parser-for-s2member/" target="_blank" rel="external">Custom Email Parser</a> inside your AWeber account.</p>'."\n";
131
+ echo '<p>Log into AWeber, and go to <em>My Lists -› Email Parser</em>. If you like, choose the PayPal Parser <em>(even if you\'re not using PayPal as your Payment Gateway)</em>. You can safely ignore the additional instructions they provide. s2Member just needs the PayPal box checked, and that\'s all. Or, even better, integrate <a href="http://www.s2member.com/kb/aweber-email-parser-for-s2member/" target="_blank" rel="external">s2Member\'s Custom Email Parser</a> for AWeber, which <strong>will improve reliability</strong> and flexibility.</p>'."\n";
132
+ echo '<p><em><strong>AWeber Tip:</strong> If you want your Members to be subscribed to multiple AWeber List IDs at the same time, instead of comma-delimiting those List IDs here; we suggest a single List ID in your s2Member integration; then use <a href="https://help.aweber.com/entries/21696463-Can-I-Add-Subscribers-to-More-Than-One-List-At-Once-" target="_blank" rel="external">AWeber Automation Rules</a> for this. Automation Rules can also reduce the number of email confirmation notices that Members receive.</em></p>'."\n";
133
  do_action("ws_plugin__s2member_during_els_ops_page_during_left_sections_during_aweber", get_defined_vars());
134
 
135
  echo '<table class="form-table">'."\n";
159
 
160
  echo '</tbody>'."\n";
161
  echo '</table>'."\n";
162
+
163
  echo '<div class="ws-menu-page-hr"></div>'."\n";
164
+
165
  echo '<div class="ws-menu-page-hilite" style="border-radius:3px; padding:5px;">'."\n";
166
+ echo '<p style="font-size:110%; margin-top:0;"><span>We HIGHLY recommend that you enable logging during your initial testing phase. Logs produce lots of useful details that can help in debugging. Logs can help you find issues in your configuration and/or problems during AWeber processing. See: <a href="'.esc_attr(admin_url("/admin.php?page=ws-plugin--s2member-logs")).'">Log Files (Debug)</a>.</span></p>'."\n";
167
  echo '<p style="font-size:110%; margin-bottom:0;"><span class="ws-menu-page-error">However, it is VERY IMPORTANT to disable logging once you go live. Log files may contain personally identifiable information, credit card numbers, secret API credentials, passwords and/or other sensitive information. We STRONGLY suggest that logging be disabled on a live site (for security reasons).</span></p>'."\n";
168
  echo '</div>'."\n";
169
+
170
  echo '</div>'."\n";
171
 
172
  echo '</div>'."\n";
243
  echo '<div class="ws-menu-page-section ws-plugin--s2member-opt-out-section">'."\n";
244
  echo '<h3>Automate Un-Subscribe/Opt-Out Removals (optional)</h3>'."\n";
245
  echo '<p>s2Member can automatically <em>(and silently)</em> remove Users/Members from the List Servers you\'ve configured above. s2Member is also capable of automating this, based on your own personal configuration preferences. Below, you can choose which Events you consider grounds for List Removal. It is also important to point out that s2Member will ONLY remove Users/Members from the Lists you\'ve configured at the Level the User/Member is or was at during the time of the Event. For example, if a Level #1 Member is deleted, they will ONLY be removed from the List(s) you\'ve configured at Level #1. If an account is upgraded from Level #1 to Level #2, they will ONLY be removed from the List(s) you\'ve configured at Level #1. Of course, all of this is based on the configuration below.</p>'."\n";
246
+ echo '<p><em><strong>*Regarding AWeber*</strong> these will NOT work for AWeber until you <a href="http://www.s2member.com/aweber-notification-email" target="_blank" rel="external">add a Notification Email</a> to your AWeber account matching the "EMail From Address" configured in <code>s2Member -› General Options -› EMail Configuration</code>. Which is currently set to: <code>'.esc_html($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"]).'</code>. This is a required step if you want s2Member to be authenticated when it emails List Removal requests to AWeber.</em></p>'."\n";
247
  do_action("ws_plugin__s2member_during_els_ops_page_during_left_sections_during_opt_out", get_defined_vars());
248
 
249
  echo '<table class="form-table">'."\n";
287
  echo '</select><br />'."\n";
288
  echo '<em><strong>*Transitions*</strong> When/if s2Member automatically removes a Member from Lists at their current Level# (based on your configuration in the previous section), this setting tells s2Member that it should <strong>also</strong> transition the Member to any Lists you\'ve configured at the new Access Level# (i.e. Role) they are being changed to. For example, if a Member is demoted from Level #1 to Level #0, do you want s2Member to add them to the Level #0 List(s) after it removes them from the Level #1 List(s)?</em><br /><br />'."\n";
289
  echo '<em><strong>*If removed from a previous list, or NOT?*</strong> You can choose your preference above. When/if s2Member automatically transitions a mailing list subscriber, it will first try to remove the subscriber from a previous mailing list. If s2Member is able to remove the subscriber from a previous list before the transition takes place, s2Member will then make an attempt (based on your configuration) to transition the subscriber to a new/different list silently (e.g. without a new confirmation email being sent out). If s2Member is NOT able to remove a subscriber from a previous list, it can - (if configured to do so), still transition a subscriber to a new list, by sending the subscriber a new email confirmation letter (e.g. this is NOT silent, because you absolutely NEED the subscriber\'s permission in this case).</em><br /><br />'."\n";
290
+ echo '<em><strong>*Seamless with MailChimp*</strong> If enabled, Automatic List Transitions work seamlessly with MailChimp. Automatic List Transitions also work with AWeber, but AWeber will ALWAYS send the User/Member a new confirmation email, asking them to confirm changes to their mailing list subscription with you. Work is underway to improve this aspect of s2Member\'s integration with AWeber in a future release. Ideally, a Customer would be transitioned silently behind the scene with AWeber too, when appropriate.</em>'."\n";
291
  echo '</td>'."\n";
292
 
293
  echo '</tr>'."\n";
includes/menu-pages/gen-ops.inc.php CHANGED
@@ -32,7 +32,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
32
  echo '<div class="wrap ws-menu-page">' . "\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>' . "\n";
35
- echo '<h2>s2Member® General Options</h2>' . "\n";
36
 
37
  echo '<table class="ws-menu-page-table">' . "\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">' . "\n";
@@ -53,7 +53,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
53
 
54
  echo '<div class="ws-menu-page-section ws-plugin--s2member-deactivation-section">' . "\n";
55
  echo '<h3>Deactivation Safeguards (highly recommended)</h3>' . "\n";
56
- echo (is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site () && is_super_admin ()) ? '<p><em class="ws-menu-page-hilite">On a Multisite Blog Farm, this panel is ONLY visible to YOU, as a Super Administrator. s2Member automatically Safeguards everything on a Multisite Blog Farm. However, as the Super Administrator, you may turn this off; on a per-Blog basis. For example, if you\'re going to de-activate s2Member on this particular Blog, you can turn OFF the Safeguards below, so that s2Member will completely erase itself.</em></p>' . "\n" : '<p>By default, s2Member will retain all of it\'s Roles, Capabilities, and your Configuration Options when/if you deactivate s2Member from the Plugins Menu in WordPress®. However, if you would like for s2Member to erase itself completely, please choose: <code>No (upon deactivation, erase all data/options)</code>.</p>' . "\n";
57
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_deactivation", get_defined_vars ());
58
 
59
  echo '<table class="form-table">' . "\n";
@@ -94,9 +94,9 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
94
  echo '<div class="ws-menu-page-group" title="Security Encryption Key">' . "\n";
95
 
96
  echo '<div class="ws-menu-page-section ws-plugin--s2member-security-section">' . "\n";
97
- echo '<img src="' . esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]) . '/images/large-icon.png" title="s2Member (a Membership management system for WordPress®)" alt="" style="float:right; margin:0 0 0 25px; border:0;" />' . "\n";
98
  echo '<h3>Security Encryption Key (optional, for tighter security)</h3>' . "\n";
99
- echo '<p>Just like WordPress®, s2Member is open-source software. Which is wonderful. However, this also makes it possible for anyone to grab a copy of the software, and try to learn their way around its security measures. In order to keep your installation of s2Member unique/secure, you should configure a Security Encryption Key. s2Member will use your Security Encryption Key to protect itself against hackers. It does this by encrypting all sensitive information with your Key. A Security Encryption Key is unique to your installation.</p>' . "\n";
100
  echo '<p>Once you configure this, you do NOT want to change it; not ever. In fact, it is a VERY good idea to keep this backed up in a safe place, just in case you need to move your site, or re-install s2Member in the future. Some of the sensitive data that s2Member stores, will be encrypted with this Key. If you change it, that data can no longer be read, even by s2Member itself. In other words, don\'t use s2Member for six months, then decide to change your Key. That would break your installation.</p>' . "\n";
101
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_security", get_defined_vars ());
102
 
@@ -152,13 +152,13 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
152
  {
153
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_s_badge_wp_footer_code", get_defined_vars ());
154
 
155
- echo '<div class="ws-menu-page-group" title="s2Member® Security Badge">' . "\n";
156
 
157
  echo '<div class="ws-menu-page-section ws-plugin--s2member-s-badge-wp-footer-code-section">' . "\n";
158
  echo '<h3>Security Badge &amp; Footer Configuration (optional)</h3>' . "\n";
159
  echo '<div class="ws-menu-page-right">' . c_ws_plugin__s2member_utilities::s_badge_gen ("1", true, true) . '</div>' . "\n";
160
- echo '<p>An s2Member® Security Badge <em>(optional)</em>, can be used to express your site\'s concern for security; demonstrating to all Users/Members that your site <em>(and the s2Member software)</em>, takes security seriously. However, in order to qualify your site, you MUST generate a Security Encryption Key <em>(previous section)</em>, and then click "Save All Changes". Only then, will s2Member officially verify your installation <em>(verification occurs automatically)</em>.</p>' . "\n";
161
- echo '<p>Once you\'ve <a href="http://www.s2member.com/kb/security-badges/" target="_blank" rel="external">properly configured all security aspects of s2Member</a>, your s2Member® Security Badge will be verified. To see the "verified" version of your Security Badge, you might need to refresh your browser after saving all changes <em>(i.e. after you create a Security Encryption Key)</em>. Also, s2Member will NOT "verify" your site if you turn off Unique IP Restrictions, Brute Force Login Protection, or if your <code>/wp-config.php</code> file lacks <a href="http://codex.wordpress.org/Editing_wp-config.php#Security_Keys" target="_blank" rel="external">Security Keys</a> <em>(each at least 60 chars in length)</em>. In addition, it\'s NOT possible for s2Member to verify your Security Badge, if your site is in a <code>localhost</code> environment; i.e. not connected to the web.</p>' . "\n";
162
  echo '<p><strong>How does s2Member know when my site is secure?</strong><br />If enabled below, an API call for "Security Badge Status", will allow web service connections to determine your status. Clicking <a href="' . esc_attr (site_url ("/?s2member_s_badge_status=1")) . '" target="_blank" rel="external">this link</a> will report <code>1</code> <em>(secure)</em>, <code>0</code> <em>(at risk)</em>, or <code>-</code> <em>(API disabled)</em>. Once all security considerations are satisfied, s2Member will report <code>1</code> <em>(secure)</em> for your installation. *Note, this simple API will NOT, and should not, report any other information. It will ONLY report the current status of your Security Badge, as determined by your installation of s2Member. When/if you install the s2Member Security Badge, s2Member will make a connection to your site "once per day", to test your status.</p>' . "\n";
163
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_s_badge_wp_footer_code", get_defined_vars ());
164
 
@@ -188,7 +188,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
188
 
189
  echo '<th>' . "\n";
190
  echo '<label for="ws-plugin--s2member-wp-footer-code">' . "\n";
191
- echo 'Customize WordPress® Footer:<br />' . "\n";
192
  echo '<small>[ <a href="#" onclick="this.$code = jQuery(\'textarea#ws-plugin--s2member-wp-footer-code\'); this.$code.val(jQuery.trim(unescape(\'' . rawurlencode ('[s2Member-Security-Badge v="1" /]') . '\')+\'\n\'+this.$code.val())); return false;">Click HERE to insert your Security Badge</a> ],<br />or use Shortcode <code>[s2Member-Security-Badge v="1" /]</code> in a Post/Page/Widget.<br />The <code>v="1"</code> attribute is a Security Badge style/variation. Try variations <code>1|2|3</code>.</small>' . "\n";
193
  echo '</label>' . "\n";
194
  echo '</th>' . "\n";
@@ -254,7 +254,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
254
 
255
  echo '<td>' . "\n";
256
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_reg_email_from_email" id="ws-plugin--s2member-reg-email-from-email" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"]) . '" /><br />' . "\n";
257
- echo 'Example: support@your-domain.com. <em class="ws-menu-page-hilite">Please read <a href="#" onclick="alert(\'Running WordPress® with an SMTP mail plugin?\\n\\nPlease be advised. If you run an SMTP mail plugin with WordPress®, be sure to configure s2Member with a valid `From:` address (i.e. one matching your SMTP configuration perhaps). Most free SMTP servers, such as Gmail® and Yahoo®, require that your `From:` header match the email address associated with your account. Please check with your SMTP service provider before attempting to configure plugins like s2Member to use a different `From:` address when sending email messages.\'); return false;">this IMPORTANT note</a></em>.' . "\n";
258
  echo '</td>' . "\n";
259
 
260
  echo '</tr>' . "\n";
@@ -292,7 +292,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
292
 
293
  echo '<td>' . "\n";
294
  echo '<select name="ws_plugin__s2member_new_user_emails_enabled" id="ws-plugin--s2member-new-user-emails-enabled">' . "\n";
295
- echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["new_user_emails_enabled"]) ? ' selected="selected"' : '') . '>No (default, use WordPress® defaults)</option>' . "\n";
296
  echo '<option value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["new_user_emails_enabled"]) ? ' selected="selected"' : '') . '>Yes (customize New User Emails with s2Member)</option>' . "\n";
297
  echo '</select>' . "\n";
298
  echo '</td>' . "\n";
@@ -306,11 +306,11 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
306
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
307
 
308
  echo '<h3 style="margin:0;">New User Email Message (<a href="#" onclick="jQuery(\'div#ws-plugin--s2member-new-user-email-details\').toggle(); return false;" class="ws-dotted-link">click to customize</a>)</h3>' . "\n";
309
- echo '<p style="margin:0;">This email is sent to all new Users/Members. It should always contain their Username/Password. In addition to this email, s2Member will also send new paying Customers a Signup Confirmation Email, which you can customize from your Dashboard, under: <code>s2Member -› PayPal® Options</code>. You may wish to customize these emails further, by providing details that are specifically geared to your site.</p>' . "\n";
310
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_new_user_email", get_defined_vars ());
311
 
312
  echo '<div id="ws-plugin--s2member-new-user-email-details" style="display:none;">' . "\n";
313
- echo (c_ws_plugin__s2member_utils_conds::bp_is_installed ()) ? '<p><em><strong>BuddyPress:</strong> please note that BuddyPress does NOT send this email to Users that register through the BuddyPress registration system. This is because BuddyPress sends each User an activation link; eliminating the need for this email all together. However, you CAN still customize s2Member\'s separate email to paying Members. See: <code>s2Member -› PayPal® Options -› Signup Confirmation Email</code>.</em></p>' . "\n" : '';
314
  echo '<table class="form-table">' . "\n";
315
  echo '<tbody>' . "\n";
316
  echo '<tr>' . "\n";
@@ -357,7 +357,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
357
  echo '<li><code>%%user_login%%</code> = The Username the Member selected during registration.</li>' . "\n";
358
  echo '<li><code>%%user_pass%%</code> = The Password selected or generated during registration.</li>' . "\n";
359
  echo '<li><code>%%user_ip%%</code> = The User\'s IP Address, detected via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
360
- echo '<li><code>%%user_id%%</code> = A unique WordPress® User ID generated during registration.</li>' . "\n";
361
  echo '<li><code>%%wp_login_url%%</code> = The full URL where Users can get logged into your site.</li>' . "\n";
362
  echo '</ul>' . "\n";
363
 
@@ -460,7 +460,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
460
  echo '<li><code>%%user_login%%</code> = The Username the Member selected during registration.</li>' . "\n";
461
  echo '<li><code>%%user_pass%%</code> = The Password selected or generated during registration.</li>' . "\n";
462
  echo '<li><code>%%user_ip%%</code> = The User\'s IP Address, detected via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
463
- echo '<li><code>%%user_id%%</code> = A unique WordPress® User ID generated during registration.</li>' . "\n";
464
  echo '<li><code>%%wp_login_url%%</code> = The full URL where Users can get logged into your site.</li>' . "\n";
465
  echo '</ul>' . "\n";
466
 
@@ -568,7 +568,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
568
  echo '<h3>Membership Levels (required, please customize these)</h3>' . "\n";
569
  echo '<p>The default Membership Levels are labeled generically; feel free to modify them as needed. s2Member supports Free Subscribers <em>(at Level #0)</em>, along with several Primary Roles for paid Membership <em>(i.e. Levels 1-4)</em>, created by the s2Member plugin.' . ((!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? ' s2Member also supports unlimited Custom Capability Packages <em>(see <code>s2Member -› API Scripting -› Custom Capabilities</code>)</em>' : '') . '. That being said, you don\'t have to use all of the Membership Levels if you don\'t want to. To use only 1 or 2 of these Levels, just design your Membership Options Page, so it only includes Payment Buttons for the Levels being used.</p>' . "\n";
570
  echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '<p><em><strong>TIP:</strong> <strong>Unlimited Membership Levels</strong> are only possible with <a href="' . esc_attr (c_ws_plugin__s2member_readmes::parse_readme_value ("Pro Module / Prices")) . '" target="_blank" rel="external">s2Member Pro</a>. However, Custom Capabilities are possible in all versions of s2Member, including the free version. Custom Capabilities are a great way to extend s2Member in creative ways. If you\'re an advanced site owner, a theme designer, or a web developer integrating s2Member for a client, please check your Dashboard, under: <code>s2Member -› API Scripting -› Custom Capabilities</code>. We also recommend <a href="http://www.s2member.com/videos/A2C07377CF60025E/" target="_blank" rel="external">this video tutorial</a>.</em></p>' . "\n" : '';
571
- echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '<p><strong>See also:</strong> These KB articles: <a href="http://www.s2member.com/kb/roles-caps/" target="_blank" rel="external">s2Member® Roles/Capabilities</a> and <a href="http://www.s2member.com/kb/simple-shortcode-conditionals/" target="_blank" rel="external">Simple Shortcode Conditionals</a>.</p>'."\n" : '';
572
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_membership_levels", get_defined_vars ());
573
 
574
  echo '<table class="form-table">' . "\n";
@@ -606,7 +606,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
606
 
607
  echo '<th style="padding-top:0;">' . "\n";
608
  echo '<label for="ws-plugin--s2member-apply-label-translations">' . "\n";
609
- echo 'Force WordPress® to use your Labels?' . "\n";
610
  echo '</label>' . "\n";
611
  echo '</th>' . "\n";
612
 
@@ -614,8 +614,8 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
614
  echo '<tr>' . "\n";
615
 
616
  echo '<td>' . "\n";
617
- echo '<input type="radio" name="ws_plugin__s2member_apply_label_translations" id="ws-plugin--s2member-apply-label-translations-0" value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["apply_label_translations"]) ? ' checked="checked"' : '') . ' /> <label for="ws-plugin--s2member-apply-label-translations-0">No</label> &nbsp;&nbsp;&nbsp; <input type="radio" name="ws_plugin__s2member_apply_label_translations" id="ws-plugin--s2member-apply-label-translations-1" value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["apply_label_translations"]) ? ' checked="checked"' : '') . ' /> <label for="ws-plugin--s2member-apply-label-translations-1">Yes, force WordPress® to use my Labels.</label><br />' . "\n";
618
- echo 'This affects your administrative Dashboard only <em>(i.e. your list of Users)</em>.<br />s2Member can force WordPress® to use your Labels instead of referencing Roles by `s2Member Level #`. If this is your first installation of s2Member, we suggest leaving this set to <code>no</code> until you\'ve had a chance to get acclimated with s2Member\'s functionality. In fact, many site owners choose to leave this off, because they find it less confusing when Roles are referred to by their s2Member Level #.' . "\n";
619
  echo '</td>' . "\n";
620
 
621
  echo '</tr>' . "\n";
@@ -625,7 +625,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
625
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
626
 
627
  echo '<input type="button" value="Reset Roles/Capabilities" class="ws-menu-page-right ws-plugin--s2member-reset-roles-button" style="min-width:175px;" />' . "\n";
628
- echo '<p>The button to the right, is a nifty tool, which allows you to reset s2Member\'s internal Roles and Capabilities that integrate with WordPress®. If you, or a developer working with you, has made attempts to alter the default <em>internal</em> Role/Capability sets that come with s2Member, and you need to reset them back to the way s2Member expects them to be, please use this tool. <em>Attn Developers: it is also possible lock-in your modified Roles/Capabilities with an s2Member Filter. Please see <a href="http://www.s2member.com/kb/roles-caps/#modifying-roles-caps" target="_blank" rel="external">this KB article for details</a>.</em></p>' . "\n";
629
 
630
  echo '</div>' . "\n";
631
 
@@ -654,7 +654,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
654
  echo '<td>' . "\n";
655
  echo '<h3 style="margin:0;">Enable This Functionality?</h3>' . "\n";
656
  echo '<select name="ws_plugin__s2member_login_reg_design_enabled" id="ws-plugin--s2member-login-reg-design-enabled">' . "\n";
657
- echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_design_enabled"]) ? ' selected="selected"' : '') . '>No (default, use WordPress® defaults)</option>' . "\n";
658
  echo '<option value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_design_enabled"]) ? ' selected="selected"' : '') . '>Yes (customize Login/Registration with s2Member)</option>' . "\n";
659
  echo '</select>' . "\n";
660
  echo '</td>' . "\n";
@@ -1091,7 +1091,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
1091
  echo '<option value="first"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_display_name"] === "first") ? ' selected="selected"' : '') . '>Yes (set Display Name to User\'s First Name)</option>' . "\n";
1092
  echo '<option value="last"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_display_name"] === "last") ? ' selected="selected"' : '') . '>Yes (set Display Name to User\'s Last Name)</option>' . "\n";
1093
  echo '<option value="login"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_display_name"] === "login") ? ' selected="selected"' : '') . '>Yes (set Display Name to User\'s Username)</option>' . "\n";
1094
- echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_display_name"]) ? ' selected="selected"' : '') . '>No (leave Display Name at default WordPress® value)</option>' . "\n";
1095
  echo '</select>' . "\n";
1096
  echo (c_ws_plugin__s2member_utils_conds::bp_is_installed ()) ? '<br /><em>* Has NO affect on BuddyPress registration form (BuddyPress always uses its full <code>Name</code> field).</em>' . "\n" : '';
1097
  echo '</td>' . "\n";
@@ -1179,7 +1179,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
1179
  echo '<h3>Login Welcome Page (required, please customize this)</h3>' . "\n";
1180
  echo '<p>Please create and/or choose an existing Page to use as the first page Members will see after logging in.</p>' . "\n";
1181
  echo (c_ws_plugin__s2member_utils_conds::bp_is_installed ()) ? '<p><em><strong>BuddyPress:</strong> s2Member integrates with BuddyPress. Your Login Welcome Page affects BuddyPress too.</em></p>' . "\n" : '';
1182
- echo '<p><em><strong>*Tip*</strong> This special Page will be protected from public access (automatically) by s2Member.</em></p>' . "\n";
1183
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/customizing-your-lwp/" target="_blank" rel="external">Customizing Your Login Welcome Page</a>.</p>'."\n";
1184
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_login_welcome_page", get_defined_vars ());
1185
 
@@ -1219,7 +1219,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
1219
 
1220
  echo '<td>' . "\n";
1221
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_redirection_override" id="ws-plugin--s2member-login-redirection-override" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_override"]) . '" /><br />' . "\n";
1222
- echo 'Or, you may configure a Special Redirection URL, if you prefer. You\'ll need to type in the full URL, starting with: <code>http://</code>. <em>A few <a href="#" onclick="alert(\'Replacement Codes:\\n\\n%%current_user_login%% = The current User\\\'s Username, lowercase.\\n%%current_user_id%% = The current User\\\'s ID.\\n%%current_user_level%% = The current User\\\'s s2Member Level.\\n%%current_user_role%% = The current User\\\'s WordPress® Role.' . ((!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '\\n%%current_user_ccaps%% = The current User\\\'s Custom Capabilities.' : '') . '\\n%%current_user_logins%% = Number of times the current User has logged in.\\n\\nFor example, if you\\\'re using BuddyPress, and you want to redirect Members to their BuddyPress Profile page after logging in, you would setup a Special Redirection URL, like this: ' . site_url ("/members/%%current_user_login%%/profile/") . '\\n\\nOr ... using %%current_user_level%%, you could have a separate Login Welcome Page for each Membership Level that you plan to offer. BuddyPress not required.\'); return false;">Replacement Codes</a> are also supported here.</em>' . "\n";
1223
  echo '</td>' . "\n";
1224
 
1225
  echo '</tr>' . "\n";
@@ -1243,7 +1243,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
1243
 
1244
  echo '<td>' . "\n";
1245
  echo '<select name="ws_plugin__s2member_login_redirection_always_http" id="ws-plugin--s2member-login-redirection-always-http">' . "\n";
1246
- echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_always_http"]) ? ' selected="selected"' : '') . '>No, do NOT modify (use WordPress® default behavior; e.g. detect URL scheme automatically)</option>' . "\n";
1247
  echo '<option value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_always_http"]) ? ' selected="selected"' : '') . '>Yes, always redirect non-administrative users to non-SSL version (e.g. always use http://)</option>' . "\n";
1248
  echo '</select><br />' . "\n";
1249
  echo 'Recommended setting: <code>Yes</code>. This is compatible w/ <a href="http://codex.wordpress.org/Administration_Over_SSL" target="_blank" rel="external"><code>FORCE_SSL_LOGIN</code></a> and/or <a href="http://codex.wordpress.org/Administration_Over_SSL" target="_blank" rel="external"><code>FORCE_SSL_ADMIN</code></a>.' . "\n";
@@ -1314,8 +1314,8 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
1314
 
1315
  echo '<div class="ws-menu-page-section ws-plugin--s2member-profile-modifications-section">' . "\n";
1316
  echo '<h3>Giving Members The Ability To Modify Their Profile</h3>' . "\n";
1317
- echo '<p>s2Member can be configured to redirect Members away from the <a href="' . esc_attr (admin_url ("/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";
1318
- 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 <em>(as the site owner)</em>, with a special Shortcode: <code>[s2Member-Profile /]</code> that you can place into your Login Welcome Page, or any Post/Page for that matter <em>(even into a Text Widget)</em>. This Shortcode produces an Inline Profile Editing Form that supports all aspects of s2Member, including Password changes; and any Custom Registration/Profile Fields that you\'ve configured with s2Member.</p>' . "\n";
1319
  echo '<p>Alternatively, s2Member also gives you the ability to send your Members to a <a href="' . esc_attr (site_url ("/?s2member_profile=1")) . '" target="_blank" rel="external">special Stand-Alone version</a>. This Stand-Alone version has been designed <em>(with a bare-bones format)</em>, intentionally. This makes it possible for you to <a href="#" onclick="if(!window.open(\'' . site_url ("/?s2member_profile=1") . '\', \'_popup\', \'width=600,height=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";
1320
  echo (c_ws_plugin__s2member_utils_conds::bp_is_installed ()) ? '<p><em><strong>BuddyPress:</strong> BuddyPress already provides Users/Members with a Profile Editing Panel, powered by your theme. If you\'ve configured Custom Registration/Profile Fields with s2Member, you can also enable s2Member\'s Profile Field integration with BuddyPress (recommended). For further details, see: <code>s2Member -› General Options -› Registration/Profile Fields</code>.</em></p>' . "\n" : '';
1321
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_profile_modifications", get_defined_vars ());
@@ -1335,7 +1335,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
1335
 
1336
  echo '<td>' . "\n";
1337
  echo '<select name="ws_plugin__s2member_force_admin_lockouts" id="ws-plugin--s2member-force-admin-lockouts">' . "\n";
1338
- echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["force_admin_lockouts"]) ? ' selected="selected"' : '') . '>No (I want to use the WordPress® default methodologies)</option>' . "\n";
1339
  echo '<option value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["force_admin_lockouts"]) ? ' selected="selected"' : '') . '>Yes (redirect to Login Welcome Page; locking all /wp-admin/ areas)</option>' . "\n";
1340
  echo '</select><br />' . "\n";
1341
  echo 'Recommended setting (<code>Yes</code>). <em><strong>*Note*</strong> When this is set to (<code>Yes</code>), s2Member will take an initiative to further safeguard ALL <code>/wp-admin/</code> areas of your installation; not just the Default Profile Panel.</em>' . "\n";
@@ -1385,8 +1385,8 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
1385
 
1386
  echo '<td>' . "\n";
1387
  echo '<select name="ws_plugin__s2member_default_url_shortener" id="ws-plugin--s2member-default-url-shortener">' . "\n";
1388
- echo '<option value="tiny_url"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["default_url_shortener"] === "tiny_url") ? ' selected="selected"' : '') . '>tinyurl.com (free tinyURL API service)</option>' . "\n";
1389
- echo '<option value="goo_gl"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["default_url_shortener"] === "goo_gl") ? ' selected="selected"' : '') . '>goo.gl (free Google® URL Shortening API service)</option>' . "\n";
1390
  echo '</select>' . "\n";
1391
  echo '</td>' . "\n";
1392
 
@@ -1404,7 +1404,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_gen_ops"))
1404
 
1405
  echo '<td>' . "\n";
1406
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_default_custom_str_url_shortener" id="ws-plugin--s2member-default-custom-str-url-shortener" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["default_custom_str_url_shortener"]) . '" /><br />' . "\n";
1407
- echo 'Your own custom URL <code>(i.e. GET request)</code>, with <code>%%s2_long_url%%</code> Replacement Code. [ <a href="#" onclick="alert(\'s2Member makes it possible for advanced site owners to use a custom URL shortening service they prefer, over the ones currently pre-integrated with s2Member. In order for this to work, your URL shortening service MUST support basic GET requests through its API (sometimes referred to as a REST or NVP API). In addition, your URL shortening service MUST be capable of returning a simple URL in the response that s2Member receives, as a result of s2Member processing the GET request you formulate. See example below.\\n\\nBitly example GET request with format=txt:\nhttp://api.bitly.com/v3/shorten?login=demo&apiKey=2d71bf07&format=txt&longUrl=%%s2_long_url%%\\n(s2Member expects a shortened URL in the response from Bitly)\\n\\n* If you configure s2Member to use your own custom URL shortening service, s2Member will try your configuration first, and if anything fails, it will fall back on its own pre-integrated backups. When configuring your URL for the GET request, s2Member makes two Replacement Codes available:\\n\\n%%s2_long_url%% = The full URL that needs to be shortened (raw URL-encoded).\\n%%s2_long_url_md5%% = An MD5 hash of the full URL (might be useful in some APIs).\\n\\n* If you have any trouble getting your URL shortening service integrated with s2Member in this way, you might take a look at this WordPress® Filter ( `ws_plugin__s2member_url_shorten` ), which s2Member makes available for advanced circumstances. Search s2Member\\\'s source code for `ws_plugin__s2member_url_shorten`.\'); return false;" tabindex="-1">click for details</a> ]<br />' . "\n";
1408
  echo '</td>' . "\n";
1409
 
1410
  echo '</tr>' . "\n";
32
  echo '<div class="wrap ws-menu-page">' . "\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>' . "\n";
35
+ echo '<h2>s2Member General Options</h2>' . "\n";
36
 
37
  echo '<table class="ws-menu-page-table">' . "\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">' . "\n";
53
 
54
  echo '<div class="ws-menu-page-section ws-plugin--s2member-deactivation-section">' . "\n";
55
  echo '<h3>Deactivation Safeguards (highly recommended)</h3>' . "\n";
56
+ echo (is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site () && is_super_admin ()) ? '<p><em class="ws-menu-page-hilite">On a Multisite Blog Farm, this panel is ONLY visible to YOU, as a Super Administrator. s2Member automatically Safeguards everything on a Multisite Blog Farm. However, as the Super Administrator, you may turn this off; on a per-Blog basis. For example, if you\'re going to de-activate s2Member on this particular Blog, you can turn OFF the Safeguards below, so that s2Member will completely erase itself.</em></p>' . "\n" : '<p>By default, s2Member will retain all of it\'s Roles, Capabilities, and your Configuration Options when/if you deactivate s2Member from the Plugins Menu in WordPress. However, if you would like for s2Member to erase itself completely, please choose: <code>No (upon deactivation, erase all data/options)</code>.</p>' . "\n";
57
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_deactivation", get_defined_vars ());
58
 
59
  echo '<table class="form-table">' . "\n";
94
  echo '<div class="ws-menu-page-group" title="Security Encryption Key">' . "\n";
95
 
96
  echo '<div class="ws-menu-page-section ws-plugin--s2member-security-section">' . "\n";
97
+ echo '<img src="' . esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]) . '/images/large-icon.png" title="s2Member (a Membership management system for WordPress)" alt="" style="float:right; margin:0 0 0 25px; border:0;" />' . "\n";
98
  echo '<h3>Security Encryption Key (optional, for tighter security)</h3>' . "\n";
99
+ echo '<p>Just like WordPress, s2Member is open-source software. Which is wonderful. However, this also makes it possible for anyone to grab a copy of the software, and try to learn their way around its security measures. In order to keep your installation of s2Member unique/secure, you should configure a Security Encryption Key. s2Member will use your Security Encryption Key to protect itself against hackers. It does this by encrypting all sensitive information with your Key. A Security Encryption Key is unique to your installation.</p>' . "\n";
100
  echo '<p>Once you configure this, you do NOT want to change it; not ever. In fact, it is a VERY good idea to keep this backed up in a safe place, just in case you need to move your site, or re-install s2Member in the future. Some of the sensitive data that s2Member stores, will be encrypted with this Key. If you change it, that data can no longer be read, even by s2Member itself. In other words, don\'t use s2Member for six months, then decide to change your Key. That would break your installation.</p>' . "\n";
101
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_security", get_defined_vars ());
102
 
152
  {
153
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_before_s_badge_wp_footer_code", get_defined_vars ());
154
 
155
+ echo '<div class="ws-menu-page-group" title="s2Member Security Badge">' . "\n";
156
 
157
  echo '<div class="ws-menu-page-section ws-plugin--s2member-s-badge-wp-footer-code-section">' . "\n";
158
  echo '<h3>Security Badge &amp; Footer Configuration (optional)</h3>' . "\n";
159
  echo '<div class="ws-menu-page-right">' . c_ws_plugin__s2member_utilities::s_badge_gen ("1", true, true) . '</div>' . "\n";
160
+ echo '<p>An s2Member Security Badge <em>(optional)</em>, can be used to express your site\'s concern for security; demonstrating to all Users/Members that your site <em>(and the s2Member software)</em>, takes security seriously. However, in order to qualify your site, you MUST generate a Security Encryption Key <em>(previous section)</em>, and then click "Save All Changes". Only then, will s2Member officially verify your installation <em>(verification occurs automatically)</em>.</p>' . "\n";
161
+ echo '<p>Once you\'ve <a href="http://www.s2member.com/kb/security-badges/" target="_blank" rel="external">properly configured all security aspects of s2Member</a>, your s2Member Security Badge will be verified. To see the "verified" version of your Security Badge, you might need to refresh your browser after saving all changes <em>(i.e. after you create a Security Encryption Key)</em>. Also, s2Member will NOT "verify" your site if you turn off Unique IP Restrictions, Brute Force Login Protection, or if your <code>/wp-config.php</code> file lacks <a href="http://codex.wordpress.org/Editing_wp-config.php#Security_Keys" target="_blank" rel="external">Security Keys</a> <em>(each at least 60 chars in length)</em>. In addition, it\'s NOT possible for s2Member to verify your Security Badge, if your site is in a <code>localhost</code> environment; i.e. not connected to the web.</p>' . "\n";
162
  echo '<p><strong>How does s2Member know when my site is secure?</strong><br />If enabled below, an API call for "Security Badge Status", will allow web service connections to determine your status. Clicking <a href="' . esc_attr (site_url ("/?s2member_s_badge_status=1")) . '" target="_blank" rel="external">this link</a> will report <code>1</code> <em>(secure)</em>, <code>0</code> <em>(at risk)</em>, or <code>-</code> <em>(API disabled)</em>. Once all security considerations are satisfied, s2Member will report <code>1</code> <em>(secure)</em> for your installation. *Note, this simple API will NOT, and should not, report any other information. It will ONLY report the current status of your Security Badge, as determined by your installation of s2Member. When/if you install the s2Member Security Badge, s2Member will make a connection to your site "once per day", to test your status.</p>' . "\n";
163
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_s_badge_wp_footer_code", get_defined_vars ());
164
 
188
 
189
  echo '<th>' . "\n";
190
  echo '<label for="ws-plugin--s2member-wp-footer-code">' . "\n";
191
+ echo 'Customize WordPress Footer:<br />' . "\n";
192
  echo '<small>[ <a href="#" onclick="this.$code = jQuery(\'textarea#ws-plugin--s2member-wp-footer-code\'); this.$code.val(jQuery.trim(unescape(\'' . rawurlencode ('[s2Member-Security-Badge v="1" /]') . '\')+\'\n\'+this.$code.val())); return false;">Click HERE to insert your Security Badge</a> ],<br />or use Shortcode <code>[s2Member-Security-Badge v="1" /]</code> in a Post/Page/Widget.<br />The <code>v="1"</code> attribute is a Security Badge style/variation. Try variations <code>1|2|3</code>.</small>' . "\n";
193
  echo '</label>' . "\n";
194
  echo '</th>' . "\n";
254
 
255
  echo '<td>' . "\n";
256
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_reg_email_from_email" id="ws-plugin--s2member-reg-email-from-email" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["reg_email_from_email"]) . '" /><br />' . "\n";
257
+ echo 'Example: support@your-domain.com. <em class="ws-menu-page-hilite">Please read <a href="#" onclick="alert(\'Running WordPress with an SMTP mail plugin?\\n\\nPlease be advised. If you run an SMTP mail plugin with WordPress, be sure to configure s2Member with a valid `From:` address (i.e. one matching your SMTP configuration perhaps). Most free SMTP servers, such as Gmail and Yahoo, require that your `From:` header match the email address associated with your account. Please check with your SMTP service provider before attempting to configure plugins like s2Member to use a different `From:` address when sending email messages.\'); return false;">this IMPORTANT note</a></em>.' . "\n";
258
  echo '</td>' . "\n";
259
 
260
  echo '</tr>' . "\n";
292
 
293
  echo '<td>' . "\n";
294
  echo '<select name="ws_plugin__s2member_new_user_emails_enabled" id="ws-plugin--s2member-new-user-emails-enabled">' . "\n";
295
+ echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["new_user_emails_enabled"]) ? ' selected="selected"' : '') . '>No (default, use WordPress defaults)</option>' . "\n";
296
  echo '<option value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["new_user_emails_enabled"]) ? ' selected="selected"' : '') . '>Yes (customize New User Emails with s2Member)</option>' . "\n";
297
  echo '</select>' . "\n";
298
  echo '</td>' . "\n";
306
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
307
 
308
  echo '<h3 style="margin:0;">New User Email Message (<a href="#" onclick="jQuery(\'div#ws-plugin--s2member-new-user-email-details\').toggle(); return false;" class="ws-dotted-link">click to customize</a>)</h3>' . "\n";
309
+ echo '<p style="margin:0;">This email is sent to all new Users/Members. It should always contain their Username/Password. In addition to this email, s2Member will also send new paying Customers a Signup Confirmation Email, which you can customize from your Dashboard, under: <code>s2Member -› PayPal Options</code>. You may wish to customize these emails further, by providing details that are specifically geared to your site.</p>' . "\n";
310
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_new_user_email", get_defined_vars ());
311
 
312
  echo '<div id="ws-plugin--s2member-new-user-email-details" style="display:none;">' . "\n";
313
+ echo (c_ws_plugin__s2member_utils_conds::bp_is_installed ()) ? '<p><em><strong>BuddyPress:</strong> please note that BuddyPress does NOT send this email to Users that register through the BuddyPress registration system. This is because BuddyPress sends each User an activation link; eliminating the need for this email all together. However, you CAN still customize s2Member\'s separate email to paying Members. See: <code>s2Member -› PayPal Options -› Signup Confirmation Email</code>.</em></p>' . "\n" : '';
314
  echo '<table class="form-table">' . "\n";
315
  echo '<tbody>' . "\n";
316
  echo '<tr>' . "\n";
357
  echo '<li><code>%%user_login%%</code> = The Username the Member selected during registration.</li>' . "\n";
358
  echo '<li><code>%%user_pass%%</code> = The Password selected or generated during registration.</li>' . "\n";
359
  echo '<li><code>%%user_ip%%</code> = The User\'s IP Address, detected via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
360
+ echo '<li><code>%%user_id%%</code> = A unique WordPress User ID generated during registration.</li>' . "\n";
361
  echo '<li><code>%%wp_login_url%%</code> = The full URL where Users can get logged into your site.</li>' . "\n";
362
  echo '</ul>' . "\n";
363
 
460
  echo '<li><code>%%user_login%%</code> = The Username the Member selected during registration.</li>' . "\n";
461
  echo '<li><code>%%user_pass%%</code> = The Password selected or generated during registration.</li>' . "\n";
462
  echo '<li><code>%%user_ip%%</code> = The User\'s IP Address, detected via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>' . "\n";
463
+ echo '<li><code>%%user_id%%</code> = A unique WordPress User ID generated during registration.</li>' . "\n";
464
  echo '<li><code>%%wp_login_url%%</code> = The full URL where Users can get logged into your site.</li>' . "\n";
465
  echo '</ul>' . "\n";
466
 
568
  echo '<h3>Membership Levels (required, please customize these)</h3>' . "\n";
569
  echo '<p>The default Membership Levels are labeled generically; feel free to modify them as needed. s2Member supports Free Subscribers <em>(at Level #0)</em>, along with several Primary Roles for paid Membership <em>(i.e. Levels 1-4)</em>, created by the s2Member plugin.' . ((!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? ' s2Member also supports unlimited Custom Capability Packages <em>(see <code>s2Member -› API Scripting -› Custom Capabilities</code>)</em>' : '') . '. That being said, you don\'t have to use all of the Membership Levels if you don\'t want to. To use only 1 or 2 of these Levels, just design your Membership Options Page, so it only includes Payment Buttons for the Levels being used.</p>' . "\n";
570
  echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '<p><em><strong>TIP:</strong> <strong>Unlimited Membership Levels</strong> are only possible with <a href="' . esc_attr (c_ws_plugin__s2member_readmes::parse_readme_value ("Pro Module / Prices")) . '" target="_blank" rel="external">s2Member Pro</a>. However, Custom Capabilities are possible in all versions of s2Member, including the free version. Custom Capabilities are a great way to extend s2Member in creative ways. If you\'re an advanced site owner, a theme designer, or a web developer integrating s2Member for a client, please check your Dashboard, under: <code>s2Member -› API Scripting -› Custom Capabilities</code>. We also recommend <a href="http://www.s2member.com/videos/A2C07377CF60025E/" target="_blank" rel="external">this video tutorial</a>.</em></p>' . "\n" : '';
571
+ echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '<p><strong>See also:</strong> These KB articles: <a href="http://www.s2member.com/kb/roles-caps/" target="_blank" rel="external">s2Member Roles/Capabilities</a> and <a href="http://www.s2member.com/kb/simple-shortcode-conditionals/" target="_blank" rel="external">Simple Shortcode Conditionals</a>.</p>'."\n" : '';
572
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_membership_levels", get_defined_vars ());
573
 
574
  echo '<table class="form-table">' . "\n";
606
 
607
  echo '<th style="padding-top:0;">' . "\n";
608
  echo '<label for="ws-plugin--s2member-apply-label-translations">' . "\n";
609
+ echo 'Force WordPress to use your Labels?' . "\n";
610
  echo '</label>' . "\n";
611
  echo '</th>' . "\n";
612
 
614
  echo '<tr>' . "\n";
615
 
616
  echo '<td>' . "\n";
617
+ echo '<input type="radio" name="ws_plugin__s2member_apply_label_translations" id="ws-plugin--s2member-apply-label-translations-0" value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["apply_label_translations"]) ? ' checked="checked"' : '') . ' /> <label for="ws-plugin--s2member-apply-label-translations-0">No</label> &nbsp;&nbsp;&nbsp; <input type="radio" name="ws_plugin__s2member_apply_label_translations" id="ws-plugin--s2member-apply-label-translations-1" value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["apply_label_translations"]) ? ' checked="checked"' : '') . ' /> <label for="ws-plugin--s2member-apply-label-translations-1">Yes, force WordPress to use my Labels.</label><br />' . "\n";
618
+ echo 'This affects your administrative Dashboard only <em>(i.e. your list of Users)</em>.<br />s2Member can force WordPress to use your Labels instead of referencing Roles by `s2Member Level #`. If this is your first installation of s2Member, we suggest leaving this set to <code>no</code> until you\'ve had a chance to get acclimated with s2Member\'s functionality. In fact, many site owners choose to leave this off, because they find it less confusing when Roles are referred to by their s2Member Level #.' . "\n";
619
  echo '</td>' . "\n";
620
 
621
  echo '</tr>' . "\n";
625
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
626
 
627
  echo '<input type="button" value="Reset Roles/Capabilities" class="ws-menu-page-right ws-plugin--s2member-reset-roles-button" style="min-width:175px;" />' . "\n";
628
+ echo '<p>The button to the right, is a nifty tool, which allows you to reset s2Member\'s internal Roles and Capabilities that integrate with WordPress. If you, or a developer working with you, has made attempts to alter the default <em>internal</em> Role/Capability sets that come with s2Member, and you need to reset them back to the way s2Member expects them to be, please use this tool. <em>Attn Developers: it is also possible lock-in your modified Roles/Capabilities with an s2Member Filter. Please see <a href="http://www.s2member.com/kb/roles-caps/#modifying-roles-caps" target="_blank" rel="external">this KB article for details</a>.</em></p>' . "\n";
629
 
630
  echo '</div>' . "\n";
631
 
654
  echo '<td>' . "\n";
655
  echo '<h3 style="margin:0;">Enable This Functionality?</h3>' . "\n";
656
  echo '<select name="ws_plugin__s2member_login_reg_design_enabled" id="ws-plugin--s2member-login-reg-design-enabled">' . "\n";
657
+ echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_design_enabled"]) ? ' selected="selected"' : '') . '>No (default, use WordPress defaults)</option>' . "\n";
658
  echo '<option value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_reg_design_enabled"]) ? ' selected="selected"' : '') . '>Yes (customize Login/Registration with s2Member)</option>' . "\n";
659
  echo '</select>' . "\n";
660
  echo '</td>' . "\n";
1091
  echo '<option value="first"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_display_name"] === "first") ? ' selected="selected"' : '') . '>Yes (set Display Name to User\'s First Name)</option>' . "\n";
1092
  echo '<option value="last"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_display_name"] === "last") ? ' selected="selected"' : '') . '>Yes (set Display Name to User\'s Last Name)</option>' . "\n";
1093
  echo '<option value="login"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_display_name"] === "login") ? ' selected="selected"' : '') . '>Yes (set Display Name to User\'s Username)</option>' . "\n";
1094
+ echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_display_name"]) ? ' selected="selected"' : '') . '>No (leave Display Name at default WordPress value)</option>' . "\n";
1095
  echo '</select>' . "\n";
1096
  echo (c_ws_plugin__s2member_utils_conds::bp_is_installed ()) ? '<br /><em>* Has NO affect on BuddyPress registration form (BuddyPress always uses its full <code>Name</code> field).</em>' . "\n" : '';
1097
  echo '</td>' . "\n";
1179
  echo '<h3>Login Welcome Page (required, please customize this)</h3>' . "\n";
1180
  echo '<p>Please create and/or choose an existing Page to use as the first page Members will see after logging in.</p>' . "\n";
1181
  echo (c_ws_plugin__s2member_utils_conds::bp_is_installed ()) ? '<p><em><strong>BuddyPress:</strong> s2Member integrates with BuddyPress. Your Login Welcome Page affects BuddyPress too.</em></p>' . "\n" : '';
1182
+ echo '<p><em><strong>*Tips*</strong> This special Page will be protected from public access (automatically) by s2Member. Also, please remember this option CANNOT be set to your Front Page (e.g. your Home Page), or to your Posts Page (e.g. your main Blog page). Please create a separate Page in WordPress &amp; designate it here as your Login Welcome Page.</em></p>' . "\n";
1183
  echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/customizing-your-lwp/" target="_blank" rel="external">Customizing Your Login Welcome Page</a>.</p>'."\n";
1184
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_login_welcome_page", get_defined_vars ());
1185
 
1219
 
1220
  echo '<td>' . "\n";
1221
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_login_redirection_override" id="ws-plugin--s2member-login-redirection-override" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_override"]) . '" /><br />' . "\n";
1222
+ echo 'Or, you may configure a Special Redirection URL, if you prefer. You\'ll need to type in the full URL, starting with: <code>http://</code>. <em>A few <a href="#" onclick="alert(\'Replacement Codes:\\n\\n%%current_user_login%% = The current User\\\'s Username, lowercase.\\n%%current_user_id%% = The current User\\\'s ID.\\n%%current_user_level%% = The current User\\\'s s2Member Level.\\n%%current_user_role%% = The current User\\\'s WordPress Role.' . ((!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '\\n%%current_user_ccaps%% = The current User\\\'s Custom Capabilities.' : '') . '\\n%%current_user_logins%% = Number of times the current User has logged in.\\n\\nFor example, if you\\\'re using BuddyPress, and you want to redirect Members to their BuddyPress Profile page after logging in, you would setup a Special Redirection URL, like this: ' . site_url ("/members/%%current_user_login%%/profile/") . '\\n\\nOr ... using %%current_user_level%%, you could have a separate Login Welcome Page for each Membership Level that you plan to offer. BuddyPress not required.\'); return false;">Replacement Codes</a> are also supported here.</em>' . "\n";
1223
  echo '</td>' . "\n";
1224
 
1225
  echo '</tr>' . "\n";
1243
 
1244
  echo '<td>' . "\n";
1245
  echo '<select name="ws_plugin__s2member_login_redirection_always_http" id="ws-plugin--s2member-login-redirection-always-http">' . "\n";
1246
+ echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_always_http"]) ? ' selected="selected"' : '') . '>No, do NOT modify (use WordPress default behavior; e.g. detect URL scheme automatically)</option>' . "\n";
1247
  echo '<option value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_always_http"]) ? ' selected="selected"' : '') . '>Yes, always redirect non-administrative users to non-SSL version (e.g. always use http://)</option>' . "\n";
1248
  echo '</select><br />' . "\n";
1249
  echo 'Recommended setting: <code>Yes</code>. This is compatible w/ <a href="http://codex.wordpress.org/Administration_Over_SSL" target="_blank" rel="external"><code>FORCE_SSL_LOGIN</code></a> and/or <a href="http://codex.wordpress.org/Administration_Over_SSL" target="_blank" rel="external"><code>FORCE_SSL_ADMIN</code></a>.' . "\n";
1314
 
1315
  echo '<div class="ws-menu-page-section ws-plugin--s2member-profile-modifications-section">' . "\n";
1316
  echo '<h3>Giving Members The Ability To Modify Their Profile</h3>' . "\n";
1317
+ echo '<p>s2Member can be configured to redirect Members away from the <a href="' . esc_attr (admin_url ("/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";
1318
+ 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 <em>(as the site owner)</em>, with a special Shortcode: <code>[s2Member-Profile /]</code> that you can place into your Login Welcome Page, or any Post/Page for that matter <em>(even into a Text Widget)</em>. This Shortcode produces an Inline Profile Editing Form that supports all aspects of s2Member, including Password changes; and any Custom Registration/Profile Fields that you\'ve configured with s2Member.</p>' . "\n";
1319
  echo '<p>Alternatively, s2Member also gives you the ability to send your Members to a <a href="' . esc_attr (site_url ("/?s2member_profile=1")) . '" target="_blank" rel="external">special Stand-Alone version</a>. This Stand-Alone version has been designed <em>(with a bare-bones format)</em>, intentionally. This makes it possible for you to <a href="#" onclick="if(!window.open(\'' . site_url ("/?s2member_profile=1") . '\', \'_popup\', \'width=600,height=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";
1320
  echo (c_ws_plugin__s2member_utils_conds::bp_is_installed ()) ? '<p><em><strong>BuddyPress:</strong> BuddyPress already provides Users/Members with a Profile Editing Panel, powered by your theme. If you\'ve configured Custom Registration/Profile Fields with s2Member, you can also enable s2Member\'s Profile Field integration with BuddyPress (recommended). For further details, see: <code>s2Member -› General Options -› Registration/Profile Fields</code>.</em></p>' . "\n" : '';
1321
  do_action ("ws_plugin__s2member_during_gen_ops_page_during_left_sections_during_profile_modifications", get_defined_vars ());
1335
 
1336
  echo '<td>' . "\n";
1337
  echo '<select name="ws_plugin__s2member_force_admin_lockouts" id="ws-plugin--s2member-force-admin-lockouts">' . "\n";
1338
+ echo '<option value="0"' . ((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["force_admin_lockouts"]) ? ' selected="selected"' : '') . '>No (I want to use the WordPress default methodologies)</option>' . "\n";
1339
  echo '<option value="1"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["force_admin_lockouts"]) ? ' selected="selected"' : '') . '>Yes (redirect to Login Welcome Page; locking all /wp-admin/ areas)</option>' . "\n";
1340
  echo '</select><br />' . "\n";
1341
  echo 'Recommended setting (<code>Yes</code>). <em><strong>*Note*</strong> When this is set to (<code>Yes</code>), s2Member will take an initiative to further safeguard ALL <code>/wp-admin/</code> areas of your installation; not just the Default Profile Panel.</em>' . "\n";
1385
 
1386
  echo '<td>' . "\n";
1387
  echo '<select name="ws_plugin__s2member_default_url_shortener" id="ws-plugin--s2member-default-url-shortener">' . "\n";
1388
+ echo '<option value="tiny_url"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["default_url_shortener"] === "tiny_url") ? ' selected="selected"' : '') . '>tinyurl.com (free tinyURL API service)</option>' . "\n";
1389
+ echo '<option value="goo_gl"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["default_url_shortener"] === "goo_gl") ? ' selected="selected"' : '') . '>goo.gl (free Google URL Shortening API service)</option>' . "\n";
1390
  echo '</select>' . "\n";
1391
  echo '</td>' . "\n";
1392
 
1404
 
1405
  echo '<td>' . "\n";
1406
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_default_custom_str_url_shortener" id="ws-plugin--s2member-default-custom-str-url-shortener" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["default_custom_str_url_shortener"]) . '" /><br />' . "\n";
1407
+ echo 'Your own custom URL <code>(i.e. GET request)</code>, with <code>%%s2_long_url%%</code> Replacement Code. [ <a href="#" onclick="alert(\'s2Member makes it possible for advanced site owners to use a custom URL shortening service they prefer, over the ones currently pre-integrated with s2Member. In order for this to work, your URL shortening service MUST support basic GET requests through its API (sometimes referred to as a REST or NVP API). In addition, your URL shortening service MUST be capable of returning a simple URL in the response that s2Member receives, as a result of s2Member processing the GET request you formulate. See example below.\\n\\nBitly example GET request with format=txt:\nhttp://api.bitly.com/v3/shorten?login=demo&apiKey=2d71bf07&format=txt&longUrl=%%s2_long_url%%\\n(s2Member expects a shortened URL in the response from Bitly)\\n\\n* If you configure s2Member to use your own custom URL shortening service, s2Member will try your configuration first, and if anything fails, it will fall back on its own pre-integrated backups. When configuring your URL for the GET request, s2Member makes two Replacement Codes available:\\n\\n%%s2_long_url%% = The full URL that needs to be shortened (raw URL-encoded).\\n%%s2_long_url_md5%% = An MD5 hash of the full URL (might be useful in some APIs).\\n\\n* If you have any trouble getting your URL shortening service integrated with s2Member in this way, you might take a look at this WordPress Filter ( `ws_plugin__s2member_url_shorten` ), which s2Member makes available for advanced circumstances. Search s2Member\\\'s source code for `ws_plugin__s2member_url_shorten`.\'); return false;" tabindex="-1">click for details</a> ]<br />' . "\n";
1408
  echo '</td>' . "\n";
1409
 
1410
  echo '</tr>' . "\n";
includes/menu-pages/info.inc.php CHANGED
@@ -32,7 +32,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_info"))
32
  echo '<div class="wrap ws-menu-page">' . "\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>' . "\n";
35
- echo '<h2>s2Member® Information</h2>' . "\n";
36
 
37
  echo '<table class="ws-menu-page-table">' . "\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">' . "\n";
32
  echo '<div class="wrap ws-menu-page">' . "\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>' . "\n";
35
+ echo '<h2>s2Member Information</h2>' . "\n";
36
 
37
  echo '<table class="ws-menu-page-table">' . "\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">' . "\n";
includes/menu-pages/integrations.inc.php CHANGED
@@ -32,7 +32,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_integrations"))
32
  echo '<div class="wrap ws-menu-page">'."\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>'."\n";
35
- echo '<h2>Other s2Member® Integrations</h2>'."\n";
36
 
37
  echo '<table class="ws-menu-page-table">'."\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">'."\n";
@@ -45,29 +45,29 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_integrations"))
45
  {
46
  do_action("ws_plugin__s2member_during_integrations_page_during_left_sections_before_bbpress", get_defined_vars());
47
 
48
- echo '<div class="ws-menu-page-group" title="bbPress® Plugin Integration (2.0+ plugin version)" default-state="open">'."\n";
49
 
50
  echo '<div class="ws-menu-page-section ws-plugin--s2member-bbpress-section">'."\n";
51
- echo '<h3>bbPress® Plugin Integration (easy peasy)</h3>'."\n";
52
  echo '<input type="button" value="Update Roles/Capabilities" class="ws-menu-page-right ws-plugin--s2member-update-roles-button" style="min-width:175px;" />'."\n";
53
- echo '<p>The plugin version of <a href="http://www.s2member.com/bbpress-plugin" target="_blank" rel="external">bbPress® 2.0+</a> integrates seamlessly with WordPress®. If bbPress® was already installed when you activated s2Member, your s2Member Roles/Capabilities are already configured to work in harmony with bbPress®. If you didn\'t, you can simply click the "Update Roles/Capabilities" button here. That\'s all it takes. Once your Roles/Capbilities are updated, s2Member and bbPress® are fully integrated with each other.</p>'."\n";
54
- echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/roles-caps/#s2-roles-caps" target="_blank" rel="external">s2Member® Roles/Capabilities (Including <strong>bbPress®</strong> Support)</a>.</p>'."\n";
55
 
56
  echo '<div class="ws-menu-page-hr"></div>'."\n";
57
 
58
- echo '<h3>bbPress® Forums and s2Member Roles/Capabilities</h3>'."\n";
59
- echo '<p>s2Member configures your Membership Roles (by default, these include: <em>s2Member Level 1</em>, <em>s2Member Level 2</em>, <em>s2Member Level 3</em>, <em>s2Member Level 4</em>), with a default set of bbPress® permissions that allow all Members to both spectate and particpate in your forums, just as if they were a WordPress® Subscriber Role (or a bbPress® Participant Role).</p>'."\n";
60
- echo '<p>bbPress® also adds some new Roles (dynamic Roles in bbPress® 2.2+) to your WordPress® installation. These include but are not limited to: <em>Keymaster</em> and <em>Moderator</em>. s2Member allows Forum Keymasters &amp; Moderators full access to the highest Membership Level you offer; just like it does with <em>Administrators</em>, <em>Editors</em>, <em>Authors</em>, and <em>Contributors</em>.</p>'."\n";
61
  echo '<p><strong>Membership Levels provide incremental access:</strong></p>'."\n";
62
- echo '<p>* A Member with Level 4 access, will also be able to access Levels 0, 1, 2 &amp; 3 <em>(plus spectate/participate in bbPress® Forums)</em>.<br />* A Member with Level 3 access, will also be able to access Levels 0, 1 &amp; 2 <em>(plus spectate/participate in bbPress® Forums)</em>.<br />* A Member with Level 2 access, will also be able to access Levels 0 &amp; 1 <em>(plus spectate/participate in bbPress® Forums)</em>.<br />* A Member with Level 1 access, will also be able to access Level 0 <em>(plus spectate/participate in bbPress® Forums)</em>.<br />* A Subscriber with Level 0 access, will ONLY be able to access Level 0 <em>(plus spectate/participate in bbPress® Forums)</em>.<br />* A public Visitor will have NO access to protected content <em>(and no special access to bbPress® Forums)</em>.</p>'."\n";
63
- echo '<p><em>* WordPress® Subscribers <strong class="ws-menu-page-hilite">and bbPress® Spectators/Participants</strong> are at Membership Level 0. If you\'re allowing Open Registration via s2Member, Subscribers will be at Level 0 (a Free Subscriber).</em></p>'."\n";
64
- echo '<p><em>* WordPress® Administrators, Editors, Authors, Contributors, <strong class="ws-menu-page-hilite">and bbPress® Keymasters/Moderators</strong> have Level 4 access, with respect to s2Member. All of their other Roles/Capabilities are left untouched.</em></p>'."\n";
65
 
66
  echo '<div class="ws-menu-page-hr"></div>'."\n";
67
 
68
- echo '<h3>Protecting Content Introduced by bbPress®</h3>'."\n";
69
- echo '<p>You can protect individual Forum Topics/Posts/Replies at different Levels with s2Member, or even with Custom Capabilities. Forum Topics/Posts/Replies are integrated by bbPress® internally as "Custom Post Types", which can be protected by s2Member either through Post Level Access Restrictions, or through URI Level Access Restrictions (recommended). If you choose to use Post Level Access Restrictions, please remember that s2Member will provide you with drop-down menus whenever you add or edit Forum Topics/Posts/Replies to make things easier for you.</p>'."\n";
70
- echo '<p>Regarding s2Member\'s Post Level Access Restrictions with bbPress®. Before you decide to use Post Level Access Restrictions, please take a look at: <code>s2Member -› Restriction Options -› URI Access Restrictions</code> and consider the following limitations in the current release of s2Member. It is currently NOT possible to protect a Forum, and have all Topics inside that Forum protected automatically. In order to accomplish that, you\'ll need to use s2Member\'s URI Access Restrictions. Also, s2Member is currently NOT capable of protecting Topic Tags; but you can use URI Restrictions for these also.</p>'."\n";
71
 
72
  do_action("ws_plugin__s2member_during_integrations_page_during_left_sections_during_bbpress", get_defined_vars());
73
  echo '</div>'."\n";
32
  echo '<div class="wrap ws-menu-page">'."\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>'."\n";
35
+ echo '<h2>Other s2Member Integrations</h2>'."\n";
36
 
37
  echo '<table class="ws-menu-page-table">'."\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">'."\n";
45
  {
46
  do_action("ws_plugin__s2member_during_integrations_page_during_left_sections_before_bbpress", get_defined_vars());
47
 
48
+ echo '<div class="ws-menu-page-group" title="bbPress Plugin Integration (2.0+ plugin version)" default-state="open">'."\n";
49
 
50
  echo '<div class="ws-menu-page-section ws-plugin--s2member-bbpress-section">'."\n";
51
+ echo '<h3>bbPress Plugin Integration (easy peasy)</h3>'."\n";
52
  echo '<input type="button" value="Update Roles/Capabilities" class="ws-menu-page-right ws-plugin--s2member-update-roles-button" style="min-width:175px;" />'."\n";
53
+ echo '<p>The plugin version of <a href="http://www.s2member.com/bbpress-plugin" target="_blank" rel="external">bbPress 2.0+</a> integrates seamlessly with WordPress. If bbPress was already installed when you activated s2Member, your s2Member Roles/Capabilities are already configured to work in harmony with bbPress. If you didn\'t, you can simply click the "Update Roles/Capabilities" button here. That\'s all it takes. Once your Roles/Capbilities are updated, s2Member and bbPress are fully integrated with each other.</p>'."\n";
54
+ echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/roles-caps/#s2-roles-caps" target="_blank" rel="external">s2Member Roles/Capabilities (Including <strong>bbPress</strong> Support)</a>.</p>'."\n";
55
 
56
  echo '<div class="ws-menu-page-hr"></div>'."\n";
57
 
58
+ echo '<h3>bbPress Forums and s2Member Roles/Capabilities</h3>'."\n";
59
+ echo '<p>s2Member configures your Membership Roles (by default, these include: <em>s2Member Level 1</em>, <em>s2Member Level 2</em>, <em>s2Member Level 3</em>, <em>s2Member Level 4</em>), with a default set of bbPress permissions that allow all Members to both spectate and particpate in your forums, just as if they were a WordPress Subscriber Role (or a bbPress Participant Role).</p>'."\n";
60
+ echo '<p>bbPress also adds some new Roles (dynamic Roles in bbPress 2.2+) to your WordPress installation. These include but are not limited to: <em>Keymaster</em> and <em>Moderator</em>. s2Member allows Forum Keymasters &amp; Moderators full access to the highest Membership Level you offer; just like it does with <em>Administrators</em>, <em>Editors</em>, <em>Authors</em>, and <em>Contributors</em>.</p>'."\n";
61
  echo '<p><strong>Membership Levels provide incremental access:</strong></p>'."\n";
62
+ echo '<p>* A Member with Level 4 access, will also be able to access Levels 0, 1, 2 &amp; 3 <em>(plus spectate/participate in bbPress Forums)</em>.<br />* A Member with Level 3 access, will also be able to access Levels 0, 1 &amp; 2 <em>(plus spectate/participate in bbPress Forums)</em>.<br />* A Member with Level 2 access, will also be able to access Levels 0 &amp; 1 <em>(plus spectate/participate in bbPress Forums)</em>.<br />* A Member with Level 1 access, will also be able to access Level 0 <em>(plus spectate/participate in bbPress Forums)</em>.<br />* A Subscriber with Level 0 access, will ONLY be able to access Level 0 <em>(plus spectate/participate in bbPress Forums)</em>.<br />* A public Visitor will have NO access to protected content <em>(and no special access to bbPress Forums)</em>.</p>'."\n";
63
+ echo '<p><em>* WordPress Subscribers <strong class="ws-menu-page-hilite">and bbPress Spectators/Participants</strong> are at Membership Level 0. If you\'re allowing Open Registration via s2Member, Subscribers will be at Level 0 (a Free Subscriber).</em></p>'."\n";
64
+ echo '<p><em>* WordPress Administrators, Editors, Authors, Contributors, <strong class="ws-menu-page-hilite">and bbPress Keymasters/Moderators</strong> have Level 4 access, with respect to s2Member. All of their other Roles/Capabilities are left untouched.</em></p>'."\n";
65
 
66
  echo '<div class="ws-menu-page-hr"></div>'."\n";
67
 
68
+ echo '<h3>Protecting Content Introduced by bbPress</h3>'."\n";
69
+ echo '<p>You can protect individual Forum Topics/Posts/Replies at different Levels with s2Member, or even with Custom Capabilities. Forum Topics/Posts/Replies are integrated by bbPress internally as "Custom Post Types", which can be protected by s2Member either through Post Level Access Restrictions, or through URI Level Access Restrictions (recommended). If you choose to use Post Level Access Restrictions, please remember that s2Member will provide you with drop-down menus whenever you add or edit Forum Topics/Posts/Replies to make things easier for you.</p>'."\n";
70
+ echo '<p>Regarding s2Member\'s Post Level Access Restrictions with bbPress. Before you decide to use Post Level Access Restrictions, please take a look at: <code>s2Member -› Restriction Options -› URI Access Restrictions</code> and consider the following limitations in the current release of s2Member. It is currently NOT possible to protect a Forum, and have all Topics inside that Forum protected automatically. In order to accomplish that, you\'ll need to use s2Member\'s URI Access Restrictions. Also, s2Member is currently NOT capable of protecting Topic Tags; but you can use URI Restrictions for these also.</p>'."\n";
71
 
72
  do_action("ws_plugin__s2member_during_integrations_page_during_left_sections_during_bbpress", get_defined_vars());
73
  echo '</div>'."\n";
includes/menu-pages/js-c-warning.inc.php CHANGED
@@ -30,8 +30,8 @@ if (!class_exists ("c_ws_plugin__s2member_menu_pages_js_c_warning"))
30
  public function __construct ()
31
  {
32
  echo '<p style="margin-top:0;"><strong>Dashboard JavaScript Conflict</strong></p>' . "\n";
33
- echo '<p>Something is conflicting with the jQuery JavaScript framework, which s2Member® uses; causing this warning to be visible to you.</p>' . "\n";
34
- echo '<p style="margin-bottom:0;">Please deactivate one other plugin at a time until you find the culprit. Or, in Firefox®, see <code>Tools -› Error Console</code>.</p>';
35
  }
36
  }
37
  }
30
  public function __construct ()
31
  {
32
  echo '<p style="margin-top:0;"><strong>Dashboard JavaScript Conflict</strong></p>' . "\n";
33
+ echo '<p>Something is conflicting with the jQuery JavaScript framework, which s2Member uses; causing this warning to be visible to you.</p>' . "\n";
34
+ echo '<p style="margin-bottom:0;">Please deactivate one other plugin at a time until you find the culprit. Or, in Firefox, see <code>Tools -› Error Console</code>.</p>';
35
  }
36
  }
37
  }
includes/menu-pages/logs.inc.php CHANGED
@@ -32,7 +32,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_logs"))
32
  echo '<div class="wrap ws-menu-page">'."\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>'."\n";
35
- echo '<h2>s2Member® Logs (for Debugging Purposes)</h2>'."\n";
36
 
37
  echo '<table class="ws-menu-page-table">'."\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">'."\n";
@@ -45,26 +45,26 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_logs"))
45
  {
46
  do_action ("ws_plugin__s2member_during_logs_page_during_left_sections_before_help", get_defined_vars ());
47
 
48
- echo '<div class="ws-menu-page-group" title="Getting Help w/ s2Member®">' . "\n";
49
 
50
  echo '<div class="ws-menu-page-section ws-plugin--s2member-help">' . "\n";
51
- echo '<h3>Getting Help w/ s2Member® (Troubleshooting)</h3>' . "\n";
52
- echo '<p>s2Member® is pretty easy to setup and install initially. Most of the official documentation is right here in your Dashboard (i.e. there is a lot of inline documentation built into the software). That being said, it CAN take some time to master everything there is to know about s2Member\'s advanced features. If you need assistance with s2Member®, please search the <a href="http://www.s2member.com/kb/" target="_blank" rel="external">s2Member® Knowledge Base</a>, <a href="http://www.s2member.com/videos/" target="_blank" rel="external">Video Tutorials</a>, <a href="http://www.s2member.com/forums/" target="_blank" rel="external">Forums</a> and <a href="http://www.s2member.com/codex/" target="_blank" rel="external">Codex</a>. If you are planning to do something creative with s2Member®, you might want to <a href="http://jobs.wordpress.net" target="_blank" rel="external">hire a freelance developer</a> to assist you.</p>' . "\n";
53
- echo '<p><strong>See also:</strong> <a href="http://www.s2member.com/kb/common-troubleshooting-tips/" target="_blank" rel="external">s2Member® Troubleshooting Guide</a> (please read this first if you\'re having trouble).</p>'."\n";
54
 
55
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
56
 
57
  echo '<h3>Testing Server Compatibility</h3>'."\n";
58
- echo '<p>Please download the <a href="http://www.s2member.com/r/server-check-tool/">s2Member® Server Scanner</a>. Unzip, upload via FTP; then open in a browser for a full report.</p>'."\n";
59
 
60
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
61
 
62
  echo '<h3>Troubleshooting Payment Gateway Integrations</h3>'."\n";
63
- echo '<p>Please use the s2Member® Log Viewer (below). Log files can be very helpful.</p>'."\n";
64
 
65
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
66
 
67
- echo '<h3>Search s2Member® KB Articles, Forums, Codex and more<em>!</em></h3>'."\n";
68
  echo '<form method="get" action="http://www.s2member.com/quick-s.php" target="_blank" onsubmit="if(this.q.value === \'enter search terms...\') this.q.value = \'\';">'."\n";
69
  echo '<p><input type="text" name="q" value="enter search terms..." style="width:60%;" onfocus="if(this.value === \'enter search terms...\') this.value = \'\';" onblur="if(this.value === \'\') this.value = \'enter search terms...\';" /><input type="submit" value="Search" /></p>'."\n";
70
  echo '</form>'."\n";
@@ -80,15 +80,15 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_logs"))
80
  {
81
  do_action("ws_plugin__s2member_during_logs_page_during_left_sections_before_log_settings", get_defined_vars());
82
 
83
- echo '<div class="ws-menu-page-group" title="Logging Configuration (for Debugging)">'."\n";
84
  echo '<div class="ws-menu-page-section ws-plugin--s2member-log-settings-section">'."\n";
85
 
86
- echo '<h3>s2Member® Logging Configuration (for Debugging Purposes)</h3>'."\n";
87
 
88
  echo '<div class="ws-menu-page-hilite" style="border-radius:3px; padding:5px;">'."\n";
89
- echo '<p style="font-size:110%; margin-top:0;"><span>We HIGHLY recommend that you enable logging during your initial testing phase. Logs produce lots of useful details that can help in debugging. Logs can help you find issues in your configuration and/or problems that occur during processing. Enable logging here, and then view your log files below; in the s2Member® Log Viewer.</span></p>'."\n";
90
  echo '<p style="font-size:110%; margin-bottom:0;"><span class="ws-menu-page-error">However, it is VERY IMPORTANT to disable logging once you go live. Log files may contain personally identifiable information, credit card numbers, secret API credentials, passwords and/or other sensitive information. We STRONGLY suggest that logging be disabled on a live site (for security reasons).</span></p>'."\n";
91
- echo '<p style="font-size:110%; margin-bottom:0;"><span>Regarding s2Member® Security Badges. If debug logging is enabled, your site will NOT qualify for an s2Member® Security Badge until you disable logging (and you must ALSO download, and then delete any existing log files). For further details, please see KB Article: <a href="http://www.s2member.com/kb/security-badges/" target="_blank" rel="external">s2Member® Security Badges</a>.</span></p>'."\n";
92
  echo '</div>'."\n";
93
 
94
  echo '<div class="ws-menu-page-hr"></div>'."\n";
@@ -113,7 +113,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_logs"))
113
 
114
  echo '<td>'."\n";
115
  echo '<input type="radio" name="ws_plugin__s2member_gateway_debug_logs" id="ws-plugin--s2member-gateway-debug-logs-0" value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["gateway_debug_logs"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-gateway-debug-logs-0">No</label> &nbsp;&nbsp;&nbsp; <input type="radio" name="ws_plugin__s2member_gateway_debug_logs" id="ws-plugin--s2member-gateway-debug-logs-1" value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["gateway_debug_logs"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-gateway-debug-logs-1">Yes, enable debugging w/ HTTP, API, IPN &amp; Return Page logging (and List Server API logs too).</label><br />'."\n";
116
- echo '<em>This enables logging overall. Includes s2Member® HTTP, API, IPN and Return Page logging. Also logs any List Server integrations.</em><br />'."\n";
117
  echo '<em>* Use only for debugging. This should NEVER be enabled on a live site.<br />* The log files are stored here: <code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["logs_dir"])).'</code></em>'."\n";
118
  echo '</td>'."\n";
119
 
@@ -130,8 +130,8 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_logs"))
130
  echo '<tr>'."\n";
131
 
132
  echo '<td>'."\n";
133
- echo '<input type="radio" name="ws_plugin__s2member_gateway_debug_logs_extensive" id="ws-plugin--s2member-gateway-debug-logs-extensive-0" value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["gateway_debug_logs_extensive"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-gateway-debug-logs-extensive-0">No</label> &nbsp;&nbsp;&nbsp; <input type="radio" name="ws_plugin__s2member_gateway_debug_logs_extensive" id="ws-plugin--s2member-gateway-debug-logs-extensive-1" value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["gateway_debug_logs_extensive"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-gateway-debug-logs-extensive-1">Yes, enable debugging w/ HTTP connection logging for ALL of WordPress®.</label><br />'."\n";
134
- echo '<em>This enables HTTP connection logging for ALL of WordPress® (quite extensive).<br />* Use only for debugging. This should NEVER be enabled on a live site.<br />* Creates the additional log file: <code>wp-http-api-debug.log</code></em>'."\n";
135
  echo '</td>'."\n";
136
 
137
  echo '</tr>'."\n";
@@ -154,7 +154,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_logs"))
154
  {
155
  do_action("ws_plugin__s2member_during_logs_page_during_left_sections_before_logs", get_defined_vars());
156
 
157
- echo '<div class="ws-menu-page-group" title="s2Member® Log Viewer (for Debugging Purposes)" default-state="open">'."\n";
158
 
159
  echo '<div class="ws-menu-page-section ws-plugin--s2member-logs-section">'."\n";
160
  echo '<h3>Debugging Tools/Tips &amp; Other Important Details (<a href="#" onclick="jQuery(\'div#ws-plugin--s2member-debugging-tips-details\').toggle(); return false;" class="ws-dotted-link">click here to toggle</a>)</h3>'."\n";
@@ -163,7 +163,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_logs"))
163
 
164
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
165
 
166
- echo '<form method="post" onsubmit="if(!confirm(\'Archive all existing log files?\n\nAll of your current log files will be archived (e.g. they will simply be renamed with an ARCHIVED tag &amp; date in their file name); and new log files will be created automatically the next time s2Member® logs something on your installation.\n\nPlease click OK to confirm this action.\')) return false;">'."\n";
167
  echo '<input type="hidden" name="ws_plugin__s2member_logs_archive_start_fresh" value="'.esc_attr(wp_create_nonce ("ws-plugin--s2member-logs-archive-start-fresh")).'" />'."\n";
168
  echo '<input type="submit" value="Archive All Current Log Files" class="ws-menu-page-right ws-plugin--s2member-archive-logs-start-fresh-button" style="clear:right; min-width:200px;" />'."\n";
169
  echo '</form>'."\n";
@@ -178,15 +178,15 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_logs"))
178
  echo '<input type="submit" value="Download All Log Files (Zip File)" class="ws-menu-page-right ws-plugin--s2member-logs-download-zip-button" style="clear:right; min-width:200px;" />'."\n";
179
  echo '</form>'."\n";
180
 
181
- echo '<p><strong>Debugging Tips:</strong> &nbsp;&nbsp; It is normal to see a few errors in your log files. This is because s2Member® logs ALL of its communication with Payment Gateways. Everything — not just successes. With that in mind, there will be some failures that s2Member® expects (to a certain extent); and s2Member® deals with these gracefully. What you\'re looking for here, are things that jump right out at you as being a major issue (e.g. when s2Member® makes a point of providing details to you in a log entry about problems that should be corrected on your installation). Please read carefully.</p>'."\n";
182
- echo '<p><strong>Test Transaction Tips:</strong> &nbsp;&nbsp; Generally speaking, it is best to run test transactions for yourself. Be sure to run your final test transactions against a live Payment Gateway that is NOT in Sandbox/Test Mode (<a href="#" onclick="alert(\'While some Payment Gateways make it possible for you to run test transactions in Sandbox/Test Mode, these are NOT a reliable way to test s2Member®.\n\nOften times (particularly with PayPal®) Sandbox/Test mode behaves somewhat differently — often with buggy behavior. This can really create frustration for site owners. Therefore, it is always a good idea to run low dollar test transactions against a live Payment Gateway.\n\nAlso, please be sure that you are NOT logged in as an Administrator when running test transactions. For most test transactions, you will want to be completely logged out of your site before completing checkout (just a new Customer would be). If you are testing an upgrade or downgrade (where you DO need to be logged-in), please do NOT attempt this under an Administrative account. s2Member® will NOT upgrade/downgrade Administrative accounts — for security purposes.\'); return false;">click here for details</a>). After running test transactions, please review the log file entries pertaining to your transaction. Does s2Member® report any major issues? If so, please read through any details that s2Member® provides in the log file. If you need assistance, please <a href="http://www.s2member.com/quick-s.php" target="_blank" rel="external">search s2Member.com</a> for answers to common questions.</p>'."\n";
183
- echo '<p><strong>s2 Core Processors:</strong> &nbsp;&nbsp; It is normal to have a <code>paypay-ipn.log</code> and/or a <code>paypay-rtn.log</code> file at all times. Ultimately, all Payment Gateway integrations supported by s2Member® pass through it\'s core PayPal® processors; even if you\'ve integrated with another Payment Gateway. If you are having trouble, and you don\'t find any errors in your Payment Gateway log files, please check the <code>paypay-ipn.log</code> and <code>paypay-rtn.log</code> files too. Regarding s2Member® Pro Forms... If you\'ve integrated s2Member® Pro Forms, you will NOT have a <code>paypay-rtn.log</code> file, because that particular processor is not used with Pro Form integrations. However, you will have a <code>paypay-ipn.log</code> file, and you will need to make a point of inspecting this file to ensure there were no post-processing issues.</p>'."\n";
184
- echo '<p><strong>s2 HTTP API Logs:</strong> &nbsp;&nbsp; If s2Member® is not behaving as expected, and you cannot find errors anywhere in your Payment Gateway log files (or with any core PayPal® processors), please review your <code>s2-http-api-debug.log</code> file too. Look for any HTTP connections where s2Member® is getting <code>403</code>, <code>404</code>, <code>503</code> errors from your server. This can sometimes happen due to <a href="http://www.s2member.com/kb/mod-security-random-503-403-errors/" target="_blank" rel="external">paranoid Mod Security configurations</a>, and it may require you to contact your hosting company for assistance.</p>'."\n";
185
- echo '<p style="font-style:italic;"><strong>Archived Log Files:</strong> &nbsp;&nbsp; All s2Member® log files are stored here: <code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["logs_dir"])).'</code>. Any log files that contain the word <code>ARCHIVED</code> in their name, are files that reached a size of more than 2MB, so s2Member® archived them automatically to prevent any single log file from becoming too large. Archived log file names will also contain the date/time they were archived by s2Member®. These archived log files typically contain much older (and possibly outdated) log entries.</p>'."\n";
186
 
187
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
188
 
189
- echo '<h3>s2Member® Log File Descriptions (for ALL possible log file names)</h3>'."\n";
190
 
191
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
192
 
32
  echo '<div class="wrap ws-menu-page">'."\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>'."\n";
35
+ echo '<h2>s2Member Logs</h2>'."\n";
36
 
37
  echo '<table class="ws-menu-page-table">'."\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">'."\n";
45
  {
46
  do_action ("ws_plugin__s2member_during_logs_page_during_left_sections_before_help", get_defined_vars ());
47
 
48
+ echo '<div class="ws-menu-page-group" title="Getting Help">' . "\n";
49
 
50
  echo '<div class="ws-menu-page-section ws-plugin--s2member-help">' . "\n";
51
+ echo '<h3>Getting Help w/ s2Member (Troubleshooting)</h3>' . "\n";
52
+ echo '<p>s2Member is pretty easy to setup and install initially. Most of the official documentation is right here in your Dashboard (i.e. there is a lot of inline documentation built into the software). That being said, it CAN take some time to master everything there is to know about s2Member\'s advanced features. If you need assistance with s2Member, please search the <a href="http://www.s2member.com/kb/" target="_blank" rel="external">s2Member Knowledge Base</a>, <a href="http://www.s2member.com/videos/" target="_blank" rel="external">Video Tutorials</a>, <a href="http://www.s2member.com/forums/" target="_blank" rel="external">Forums</a> and <a href="http://www.s2member.com/codex/" target="_blank" rel="external">Codex</a>. If you are planning to do something creative with s2Member, you might want to <a href="http://jobs.wordpress.net" target="_blank" rel="external">hire a freelance developer</a> to assist you.</p>' . "\n";
53
+ echo '<p><strong>See also:</strong> <a href="http://www.s2member.com/kb/common-troubleshooting-tips/" target="_blank" rel="external">s2Member Troubleshooting Guide</a> (please read this first if you\'re having trouble).</p>'."\n";
54
 
55
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
56
 
57
  echo '<h3>Testing Server Compatibility</h3>'."\n";
58
+ echo '<p>Please download the <a href="http://www.s2member.com/r/server-check-tool/">s2Member Server Scanner</a>. Unzip, upload via FTP; then open in a browser for a full report.</p>'."\n";
59
 
60
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
61
 
62
  echo '<h3>Troubleshooting Payment Gateway Integrations</h3>'."\n";
63
+ echo '<p>Please use the s2Member Log Viewer (below). Log files can be very helpful.</p>'."\n";
64
 
65
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
66
 
67
+ echo '<h3>Search s2Member KB Articles, Forums, Codex and more<em>!</em></h3>'."\n";
68
  echo '<form method="get" action="http://www.s2member.com/quick-s.php" target="_blank" onsubmit="if(this.q.value === \'enter search terms...\') this.q.value = \'\';">'."\n";
69
  echo '<p><input type="text" name="q" value="enter search terms..." style="width:60%;" onfocus="if(this.value === \'enter search terms...\') this.value = \'\';" onblur="if(this.value === \'\') this.value = \'enter search terms...\';" /><input type="submit" value="Search" /></p>'."\n";
70
  echo '</form>'."\n";
80
  {
81
  do_action("ws_plugin__s2member_during_logs_page_during_left_sections_before_log_settings", get_defined_vars());
82
 
83
+ echo '<div class="ws-menu-page-group" title="Logging Configuration">'."\n";
84
  echo '<div class="ws-menu-page-section ws-plugin--s2member-log-settings-section">'."\n";
85
 
86
+ echo '<h3>Logging Configuration</h3>'."\n";
87
 
88
  echo '<div class="ws-menu-page-hilite" style="border-radius:3px; padding:5px;">'."\n";
89
+ echo '<p style="font-size:110%; margin-top:0;"><span>We HIGHLY recommend that you enable logging during your initial testing phase. Logs produce lots of useful details that can help in debugging. Logs can help you find issues in your configuration and/or problems that occur during processing. Enable logging here, and then view your log files below; in the s2Member Log Viewer.</span></p>'."\n";
90
  echo '<p style="font-size:110%; margin-bottom:0;"><span class="ws-menu-page-error">However, it is VERY IMPORTANT to disable logging once you go live. Log files may contain personally identifiable information, credit card numbers, secret API credentials, passwords and/or other sensitive information. We STRONGLY suggest that logging be disabled on a live site (for security reasons).</span></p>'."\n";
91
+ echo '<p style="font-size:110%; margin-bottom:0;"><span>Regarding s2Member Security Badges. If debug logging is enabled, your site will NOT qualify for an s2Member Security Badge until you disable logging (and you must ALSO download, and then delete any existing log files). For further details, please see KB Article: <a href="http://www.s2member.com/kb/security-badges/" target="_blank" rel="external">s2Member Security Badges</a>.</span></p>'."\n";
92
  echo '</div>'."\n";
93
 
94
  echo '<div class="ws-menu-page-hr"></div>'."\n";
113
 
114
  echo '<td>'."\n";
115
  echo '<input type="radio" name="ws_plugin__s2member_gateway_debug_logs" id="ws-plugin--s2member-gateway-debug-logs-0" value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["gateway_debug_logs"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-gateway-debug-logs-0">No</label> &nbsp;&nbsp;&nbsp; <input type="radio" name="ws_plugin__s2member_gateway_debug_logs" id="ws-plugin--s2member-gateway-debug-logs-1" value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["gateway_debug_logs"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-gateway-debug-logs-1">Yes, enable debugging w/ HTTP, API, IPN &amp; Return Page logging (and List Server API logs too).</label><br />'."\n";
116
+ echo '<em>This enables logging overall. Includes s2Member HTTP, API, IPN and Return Page logging. Also logs any List Server integrations.</em><br />'."\n";
117
  echo '<em>* Use only for debugging. This should NEVER be enabled on a live site.<br />* The log files are stored here: <code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["logs_dir"])).'</code></em>'."\n";
118
  echo '</td>'."\n";
119
 
130
  echo '<tr>'."\n";
131
 
132
  echo '<td>'."\n";
133
+ echo '<input type="radio" name="ws_plugin__s2member_gateway_debug_logs_extensive" id="ws-plugin--s2member-gateway-debug-logs-extensive-0" value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["gateway_debug_logs_extensive"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-gateway-debug-logs-extensive-0">No</label> &nbsp;&nbsp;&nbsp; <input type="radio" name="ws_plugin__s2member_gateway_debug_logs_extensive" id="ws-plugin--s2member-gateway-debug-logs-extensive-1" value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["gateway_debug_logs_extensive"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-gateway-debug-logs-extensive-1">Yes, enable debugging w/ HTTP connection logging for ALL of WordPress.</label><br />'."\n";
134
+ echo '<em>This enables HTTP connection logging for ALL of WordPress (quite extensive).<br />* Use only for debugging. This should NEVER be enabled on a live site.<br />* Creates the additional log file: <code>wp-http-api-debug.log</code></em>'."\n";
135
  echo '</td>'."\n";
136
 
137
  echo '</tr>'."\n";
154
  {
155
  do_action("ws_plugin__s2member_during_logs_page_during_left_sections_before_logs", get_defined_vars());
156
 
157
+ echo '<div class="ws-menu-page-group" title="Logs Viewer" default-state="open">'."\n";
158
 
159
  echo '<div class="ws-menu-page-section ws-plugin--s2member-logs-section">'."\n";
160
  echo '<h3>Debugging Tools/Tips &amp; Other Important Details (<a href="#" onclick="jQuery(\'div#ws-plugin--s2member-debugging-tips-details\').toggle(); return false;" class="ws-dotted-link">click here to toggle</a>)</h3>'."\n";
163
 
164
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
165
 
166
+ echo '<form method="post" onsubmit="if(!confirm(\'Archive all existing log files?\n\nAll of your current log files will be archived (e.g. they will simply be renamed with an ARCHIVED tag &amp; date in their file name); and new log files will be created automatically the next time s2Member logs something on your installation.\n\nPlease click OK to confirm this action.\')) return false;">'."\n";
167
  echo '<input type="hidden" name="ws_plugin__s2member_logs_archive_start_fresh" value="'.esc_attr(wp_create_nonce ("ws-plugin--s2member-logs-archive-start-fresh")).'" />'."\n";
168
  echo '<input type="submit" value="Archive All Current Log Files" class="ws-menu-page-right ws-plugin--s2member-archive-logs-start-fresh-button" style="clear:right; min-width:200px;" />'."\n";
169
  echo '</form>'."\n";
178
  echo '<input type="submit" value="Download All Log Files (Zip File)" class="ws-menu-page-right ws-plugin--s2member-logs-download-zip-button" style="clear:right; min-width:200px;" />'."\n";
179
  echo '</form>'."\n";
180
 
181
+ echo '<p><strong>Debugging Tips:</strong> &nbsp;&nbsp; It is normal to see a few errors in your log files. This is because s2Member logs ALL of its communication with Payment Gateways. Everything — not just successes. With that in mind, there will be some failures that s2Member expects (to a certain extent); and s2Member deals with these gracefully. What you\'re looking for here, are things that jump right out at you as being a major issue (e.g. when s2Member makes a point of providing details to you in a log entry about problems that should be corrected on your installation). Please read carefully.</p>'."\n";
182
+ echo '<p><strong>Test Transaction Tips:</strong> &nbsp;&nbsp; Generally speaking, it is best to run test transactions for yourself. Be sure to run your final test transactions against a live Payment Gateway that is NOT in Sandbox/Test Mode (<a href="#" onclick="alert(\'While some Payment Gateways make it possible for you to run test transactions in Sandbox/Test Mode, these are NOT a reliable way to test s2Member.\n\nOften times (particularly with PayPal) Sandbox/Test mode behaves somewhat differently — often with buggy behavior. This can really create frustration for site owners. Therefore, it is always a good idea to run low dollar test transactions against a live Payment Gateway.\n\nAlso, please be sure that you are NOT logged in as an Administrator when running test transactions. For most test transactions, you will want to be completely logged out of your site before completing checkout (just a new Customer would be). If you are testing an upgrade or downgrade (where you DO need to be logged-in), please do NOT attempt this under an Administrative account. s2Member will NOT upgrade/downgrade Administrative accounts — for security purposes.\'); return false;">click here for details</a>). After running test transactions, please review the log file entries pertaining to your transaction. Does s2Member report any major issues? If so, please read through any details that s2Member provides in the log file. If you need assistance, please <a href="http://www.s2member.com/quick-s.php" target="_blank" rel="external">search s2Member.com</a> for answers to common questions.</p>'."\n";
183
+ echo '<p><strong>s2 Core Processors:</strong> &nbsp;&nbsp; It is normal to have a <code>paypay-ipn.log</code> and/or a <code>paypay-rtn.log</code> file at all times. Ultimately, all Payment Gateway integrations supported by s2Member pass through it\'s core PayPal processors; even if you\'ve integrated with another Payment Gateway. If you are having trouble, and you don\'t find any errors in your Payment Gateway log files, please check the <code>paypay-ipn.log</code> and <code>paypay-rtn.log</code> files too. Regarding s2Member Pro Forms... If you\'ve integrated s2Member Pro Forms, you will NOT have a <code>paypay-rtn.log</code> file, because that particular processor is not used with Pro Form integrations. However, you will have a <code>paypay-ipn.log</code> file, and you will need to make a point of inspecting this file to ensure there were no post-processing issues.</p>'."\n";
184
+ echo '<p><strong>s2 HTTP API Logs:</strong> &nbsp;&nbsp; If s2Member is not behaving as expected, and you cannot find errors anywhere in your Payment Gateway log files (or with any core PayPal processors), please review your <code>s2-http-api-debug.log</code> file too. Look for any HTTP connections where s2Member is getting <code>403</code>, <code>404</code>, <code>503</code> errors from your server. This can sometimes happen due to <a href="http://www.s2member.com/kb/mod-security-random-503-403-errors/" target="_blank" rel="external">paranoid Mod Security configurations</a>, and it may require you to contact your hosting company for assistance.</p>'."\n";
185
+ echo '<p style="font-style:italic;"><strong>Archived Log Files:</strong> &nbsp;&nbsp; All s2Member log files are stored here: <code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["logs_dir"])).'</code>. Any log files that contain the word <code>ARCHIVED</code> in their name, are files that reached a size of more than 2MB, so s2Member archived them automatically to prevent any single log file from becoming too large. Archived log file names will also contain the date/time they were archived by s2Member. These archived log files typically contain much older (and possibly outdated) log entries.</p>'."\n";
186
 
187
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
188
 
189
+ echo '<h3>s2Member Log File Descriptions (for ALL possible log file names)</h3>'."\n";
190
 
191
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
192
 
includes/menu-pages/menu-pages-s-min.js CHANGED
@@ -1 +1 @@
1
- jQuery(document).ready(function($){var esc_attr=esc_html=function(str){return String(str).replace(/"/g,"&quot;").replace(/\</g,"&lt;").replace(/\>/g,"&gt;")};if(location.href.match(/page\=ws-plugin--s2member/)){$("input.ws-plugin--s2member-update-roles-button, input.ws-plugin--s2member-reset-roles-button").click(function(){var $this=$(this);$this.val("one moment please ...");var levels='<?php echo (int)$GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]; ?>';var resetUpdate=($this.hasClass("ws-plugin--s2member-reset-roles-button"))?"Reset":"Update";$.post(ajaxurl,{action:"ws_plugin__s2member_update_roles_via_ajax",ws_plugin__s2member_update_roles_via_ajax:'<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (wp_create_nonce ("ws-plugin--s2member-update-roles-via-ajax")); ?>'},function(response){if(response==="1"){alert("s2Member's Roles/Capabilities "+((resetUpdate.toLowerCase()==="reset")?"have been successfully reset":"updated successfully")+".\nYour installation of s2Member has Membership Levels 0-"+levels+"."),$this.val(resetUpdate+" Roles/Capabilities")}else{if(response==="l"){alert("Sorry, your request failed.\ns2Member's Roles/Capabilities are locked by Filter:\nws_plugin__s2member_lock_roles_caps"),$this.val(resetUpdate+" Roles/Capabilities")}else{alert("Sorry, your request failed.\nAccess denied. Do you have the ability to `create_users`?"),$this.val(resetUpdate+" Roles/Capabilities")}}});return false})}if(location.href.match(/page\=ws-plugin--s2member-logs/)){$("input#ws-plugin--s2member-gateway-debug-logs-extensive-1").click(function(){var $this=$(this),thisChecked=(this.checked)?true:false;if(thisChecked){$("input#ws-plugin--s2member-gateway-debug-logs-1").attr("checked","checked")}});var $toggles=$("a.ws-plugin--s2member-log-file-viewport-toggle");$toggles.click(function(){$("textarea#ws-plugin--s2member-log-file-viewer").each(function(){var $viewer=$(this);if($viewer.attr("data-state")!=="expanded"){$viewer.css({height:($viewer.prop("scrollHeight")+50)+"px","overflow-y":"auto"});$toggles.html("&#8657; normalize viewport &#10073;");$viewer.attr("data-state","expanded")}else{$viewer.css({height:"auto","overflow-y":"scroll"});$toggles.html("&#8659; expand viewport &#8659;");$viewer.attr("data-state","scrolling")}});return false})}if(location.href.match(/page\=ws-plugin--s2member-mms-ops/)){$("select#ws-plugin--s2member-mms-registration-file").change(function(){if($(this).val()==="wp-signup"){var gv=$("select#ws-plugin--s2member-mms-registration-grants").val(),l0v=$("input#ws-plugin--s2member-mms-registration-blogs-level0").val();$("div#ws-plugin--s2member-mms-registration-support-package-details-wrapper").show(),$("div.ws-plugin--s2member-mms-registration-wp-login, table.ws-plugin--s2member-mms-registration-wp-login").hide(),$("div.ws-plugin--s2member-mms-registration-wp-signup, table.ws-plugin--s2member-mms-registration-wp-signup").show();$("div.ws-plugin--s2member-mms-registration-wp-signup-blogs-level0, table.ws-plugin--s2member-mms-registration-wp-signup-blogs-level0")[((gv==="all")?"show":"hide")]();$("input#ws-plugin--s2member-mms-registration-blogs-level0").val(((gv==="all")?((l0v>0)?l0v:"1"):"0"))}else{if($(this).val()==="wp-login"){var gv=$("select#ws-plugin--s2member-mms-registration-grants").val(),l0v=$("input#ws-plugin--s2member-mms-registration-blogs-level0").val();$("div#ws-plugin--s2member-mms-registration-support-package-details-wrapper").hide(),$("div.ws-plugin--s2member-mms-registration-wp-login, table.ws-plugin--s2member-mms-registration-wp-login").show(),$("div.ws-plugin--s2member-mms-registration-wp-signup, table.ws-plugin--s2member-mms-registration-wp-signup").hide();$("div.ws-plugin--s2member-mms-registration-wp-signup-blogs-level0, table.ws-plugin--s2member-mms-registration-wp-signup-blogs-level0").hide();$("input#ws-plugin--s2member-mms-registration-blogs-level0").val("0")}}}).trigger("change");$("select#ws-plugin--s2member-mms-registration-grants").change(function(){$("select#ws-plugin--s2member-mms-registration-file").trigger("change")})}if(location.href.match(/page\=ws-plugin--s2member-gen-ops/)){ws_plugin__s2member_generateSecurityKey=function(){var mt_rand=function(min,max){min=(arguments.length<1)?0:min;max=(arguments.length<2)?2147483647:max;return Math.floor(Math.random()*(max-min+1))+min};var chars="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()";for(var i=0,key="";i<64;i++){key+=chars.substr(mt_rand(0,chars.length-1),1)}$("input#ws-plugin--s2member-sec-encryption-key").val(key);return false};ws_plugin__s2member_enableSecurityKey=function(){if(confirm("Edit Key? Are you sure?\nThis could break your installation!\n\n*Note* If you've been testing s2Member, feel free to change this Key before you go live. Just don't go live, and then change it. You'll have unhappy Customers. Data corruption WILL occur! For your safety, s2Member keeps a history of the last 10 Keys that you've used. If you get yourself into a real situation, s2Member will let you revert back to a previous Key.")){$("input#ws-plugin--s2member-sec-encryption-key").removeAttr("disabled")}return false};ws_plugin__s2member_securityKeyHistory=function(){$("div#ws-plugin--s2member-sec-encryption-key-history").toggle();return false};$("select#ws-plugin--s2member-new-user-emails-enabled").change(function(){var $pluggable=$("input#ws-plugin--s2member-pluggables-wp-new-user-notification"),$this=$(this),$newUserEmails=$("div#ws-plugin--s2member-new-user-emails");if($pluggable.val()==="0"||$this.val()==="0"){($pluggable.val()==="0")?$this.attr("disabled","disabled"):$this.removeAttr("disabled");$(":input",$newUserEmails).attr("disabled","disabled"),$newUserEmails.css("opacity","0.5")}else{$this.removeAttr("disabled"),$(":input",$newUserEmails).removeAttr("disabled"),$newUserEmails.css("opacity","")}}).trigger("change");$("select#ws-plugin--s2member-login-reg-design-enabled").change(function(){var $this=$(this),$loginRegDesign=$("div#ws-plugin--s2member-login-reg-design");if($this.val()==="0"){$(":input",$loginRegDesign).attr("disabled","disabled"),$loginRegDesign.css("opacity","0.5"),$loginRegDesign.hide()}else{$(":input",$loginRegDesign).removeAttr("disabled"),$loginRegDesign.css("opacity",""),$loginRegDesign.show()}}).trigger("change");if($("input#ws-plugin--s2member-custom-reg-fields").length&&$("div#ws-plugin--s2member-custom-reg-field-configuration").length){(function(){var i,fieldDefaults,tools,table,$tools,$table;var $fields=$("input#ws-plugin--s2member-custom-reg-fields");var $configuration=$("div#ws-plugin--s2member-custom-reg-field-configuration");var fields=($fields.val())?$.JSON.parse($fields.val()):[];fields=(fields instanceof Array)?fields:[];fieldDefaults={section:"no",sectitle:"",id:"",label:"",type:"text",deflt:"",options:"",expected:"",required:"yes",levels:"all",editable:"yes",classes:"",styles:"",attrs:""};for(i=0;i<fields.length;i++){fields[i]=$.extend(true,{},fieldDefaults,fields[i])}tools='<div id="ws-plugin--s2member-custom-reg-field-configuration-tools"></div>',table='<table id="ws-plugin--s2member-custom-reg-field-configuration-table"></table>';$configuration.html(tools+table);$tools=$("div#ws-plugin--s2member-custom-reg-field-configuration-tools"),$table=$("table#ws-plugin--s2member-custom-reg-field-configuration-table");ws_plugin__s2member_customRegFieldSectionChange=function(select){var section=$(select).val();var sectitle_trs="tr.ws-plugin--s2member-custom-reg-field-configuration-tools-form-sectitle";(section==="yes")?$(sectitle_trs).css("display",""):$(sectitle_trs).css("display","none")};ws_plugin__s2member_customRegFieldTypeChange=function(select){var type=$(select).val();var deflt_trs="tr.ws-plugin--s2member-custom-reg-field-configuration-tools-form-deflt",options_trs="tr.ws-plugin--s2member-custom-reg-field-configuration-tools-form-options",expected_trs="tr.ws-plugin--s2member-custom-reg-field-configuration-tools-form-expected";(type.match(/^(text|textarea)$/))?$(deflt_trs).css("display",""):$(deflt_trs).css("display","none");(type.match(/^(select|selects|checkboxes|radios)$/))?$(options_trs).css("display",""):$(options_trs).css("display","none");(type.match(/^(text|textarea)$/))?$(expected_trs).css("display",""):$(expected_trs).css("display","none")};ws_plugin__s2member_customRegFieldDelete=function(index){var newFields=new Array();for(var i=0;i<fields.length;i++){if(i!==index){newFields.push(fields[i])}}fields=newFields,updateFields(),buildTable()};ws_plugin__s2member_customRegFieldMoveUp=function(index){if(typeof fields[index]==="object"&&typeof fields[index-1]==="object"){var prevFieldObj=fields[index-1],thisFieldObj=fields[index];fields[index-1]=thisFieldObj,fields[index]=prevFieldObj;updateFields(),buildTable()}};ws_plugin__s2member_customRegFieldMoveDown=function(index){if(typeof fields[index]==="object"&&typeof fields[index+1]==="object"){var nextFieldObj=fields[index+1],thisFieldObj=fields[index];fields[index+1]=thisFieldObj,fields[index]=nextFieldObj;updateFields(),buildTable()}};ws_plugin__s2member_customRegFieldCreate=function(){var $table=$("table#ws-plugin--s2member-custom-reg-field-configuration-tools-form"),field={};$(":input[property]",$table).each(function(){var $this=$(this),property=$this.attr("property"),val=$.trim($this.val());field[property]=val});if((field=validateField(field))){fields.push(field),updateFields(),buildTools(),buildTable(),scrollReset();setTimeout(function(){var row="tr.ws-plugin--s2member-custom-reg-field-configuration-table-row-"+(fields.length-1);alert('Field created successfully.\n* Remember to "Save All Changes".');$(row).effect("highlight",1500)},500)}};ws_plugin__s2member_customRegFieldUpdate=function(index){var $table=$("table#ws-plugin--s2member-custom-reg-field-configuration-tools-form"),field={};$(":input[property]",$table).each(function(){var $this=$(this),property=$this.attr("property"),val=$.trim($this.val());field[property]=val});if((field=validateField(field,index))){fields[index]=field,updateFields(),buildTools(),buildTable(),scrollReset();setTimeout(function(){var row="tr.ws-plugin--s2member-custom-reg-field-configuration-table-row-"+index;alert('Field updated successfully.\n* Remember to "Save All Changes".');$(row).effect("highlight",1500)},500)}};ws_plugin__s2member_customRegFieldAdd=function(){buildTools(true)};ws_plugin__s2member_customRegFieldEdit=function(index){buildTools(false,index),scrollReset()};ws_plugin__s2member_customRegFieldCancel=function(){buildTools(),scrollReset()};var validateField=function(field,index){var editing=(typeof index==="number"&&typeof fields[index]==="object")?true:false,errors=[],options,i;if(typeof field!=="object"||typeof(field=$.extend(true,{},fieldDefaults,field))!=="object"){alert("Invalid field object. Please try again.");return false}field.sectitle=(field.section==="yes")?field.sectitle:"";field.deflt=(field.type.match(/^(text|textarea)$/))?field.deflt:"";field.deflt=(field.type.match(/^(text)$/))?field.deflt.replace(/[\r\n\t ]+/g," "):field.deflt;field.options=(field.type.match(/^(select|selects|checkboxes|radios)$/))?field.options:"";field.expected=(field.type.match(/^(text|textarea)$/))?field.expected:"";if(!field.id){errors.push("Unique Field ID:\nThis is required. Please try again.")}else{if(fieldIdExists(field.id)&&(!editing||field.id!==fields[index].id)){errors.push("Unique Field ID:\nThat Field ID already exists. Please try again.")}}if(!field.label){errors.push("Field Label/Description:\nThis is required. Please try again.")}if(field.type.match(/^(select|selects|checkboxes|radios)$/)&&!field.options){errors.push("Option Configuration File:\nThis is required. Please try again.")}else{if(field.type.match(/^(select|selects|checkboxes|radios)$/)){for(i=0;i<(options=field.options.split(/[\r\n]+/)).length;i++){if(!(options[i]=$.trim(options[i])).match(/^([^\|]*)(\|)([^\|]*)(\|default)?$/)){errors.push("Option Configuration File:\nInvalid configuration at line #"+(i+1)+".");break}}field.options=$.trim(options.join("\n"))}}if(!(field.levels=field.levels.replace(/ /g,""))){errors.push("Applicable Levels:\nThis is required. Please try again.")}else{if(!field.levels.match(/^(all|[0-9,]+)$/)){errors.push("Applicable Levels:\nShould be comma-delimited Levels, or just type: all.\n(examples: 0,1,2,3,4 or type the word: all)")}}if(field.classes&&field.classes.match(/[^a-z 0-9 _ \-]/i)){errors.push("CSS Classes:\nContains invalid characters. Please try again.\n(only: alphanumerics, underscores, hyphens, spaces)")}if(field.styles&&field.styles.match(/["\=\>\<]/)){errors.push('CSS Styles:\nContains invalid characters. Please try again.\n(do NOT use these characters: = " < >)')}if(field.attrs&&field.attrs.match(/[\>\<]/)){errors.push("Other Attributes:\nContains invalid characters. Please try again.\n(do NOT use these characters: < >)")}if(errors.length>0){alert(errors.join("\n\n"));return false}else{return field}};var updateFields=function(){$fields.val(((fields.length>0)?$.JSON.stringify(fields):""))};var fieldId2Var=function(fieldId){return(typeof fieldId==="string")?$.trim(fieldId).toLowerCase().replace(/[^a-z0-9]/g,"_"):""};var fieldTypeDesc=function(type){var types={text:"Text (single line)",textarea:"Textarea (multi-line)",select:"Select Menu (drop-down)",selects:"Select Menu (multi-option)",checkbox:"Checkbox (single)",pre_checkbox:"Checkbox (pre-checked)",checkboxes:"Checkboxes (multi-option)",radios:"Radio Buttons (multi-option)"};if(typeof types[type]==="string"){return types[type]}return""};var fieldIdExists=function(fieldId){for(var i=0;i<fields.length;i++){if(fields[i].id===fieldId){return true}}};var scrollReset=function(){scrollTo(0,$("div.ws-plugin--s2member-custom-reg-fields-section").offset()["top"]-100)};var buildTools=function(adding,index){var i=0,html="",form="",w=0,h=0,editing=(typeof index==="number"&&typeof fields[index]==="object")?true:false,displayForm=(adding||editing)?true:false,field=(editing)?$.extend(true,{},fieldDefaults,fields[index]):fieldDefaults;html+='<a href="#" onclick="ws_plugin__s2member_customRegFieldAdd(); return false;">Add New Field</a>';tb_remove(),$("div#ws-plugin--s2member-custom-reg-field-configuration-thickbox-tools-form").remove();if(displayForm){form+='<div id="ws-plugin--s2member-custom-reg-field-configuration-thickbox-tools-form">';form+='<table id="ws-plugin--s2member-custom-reg-field-configuration-tools-form">';form+="<tbody>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-section">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-section">Starts A New Section?</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-section">';form+='<td colspan="2">';form+='<select property="section" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-section" onchange="ws_plugin__s2member_customRegFieldSectionChange(this);">';form+='<option value="no"'+((field.section==="no")?' selected="selected"':"")+'">No (this Field flows normally)</option>';form+='<option value="yes"'+((field.section==="yes")?' selected="selected"':"")+'">Yes (this Field begins a new section)</option>';form+="</select><br />";form+="<small>Optional. Allows Fields to be grouped into sections.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-sectitle ws-plugin--s2member-custom-reg-field-configuration-tools-form-section"'+((field.section==="yes")?"":' style="display:none;"')+'><td colspan="2"><hr /></td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-sectitle ws-plugin--s2member-custom-reg-field-configuration-tools-form-section"'+((field.section==="yes")?"":' style="display:none;"')+">";form+='<td colspan="2">';form+="Title for this new section? (optional)<br />";form+='<input type="text" property="sectitle" autocomplete="off" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-sectitle" value="'+esc_attr(field.sectitle)+'" /><br />';form+="<small>If empty, a simple divider will be used by default.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-type"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-type">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-type">Form Field Type: *</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-type">';form+='<td colspan="2">';form+='<select property="type" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-type" onchange="ws_plugin__s2member_customRegFieldTypeChange(this);">';form+='<option value="text"'+((field.type==="text")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("text"))+"</option>";form+='<option value="textarea"'+((field.type==="textarea")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("textarea"))+"</option>";form+='<option value="select"'+((field.type==="select")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("select"))+"</option>";form+='<option value="selects"'+((field.type==="selects")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("selects"))+"</option>";form+='<option value="checkbox"'+((field.type==="checkbox")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("checkbox"))+"</option>";form+='<option value="pre_checkbox"'+((field.type==="pre_checkbox")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("pre_checkbox"))+"</option>";form+='<option value="checkboxes"'+((field.type==="checkboxes")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("checkboxes"))+"</option>";form+='<option value="radios"'+((field.type==="radios")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("radios"))+"</option>";form+="</select><br />";form+="<small>The options below may change, based on the Field Type you choose here.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-label"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-label">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-label">Field Label/Desc: *</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-label">';form+='<td colspan="2">';form+='<input type="text" property="label" autocomplete="off" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-label" value="'+esc_attr(field.label)+'" /><br />';form+="<small>Examples: <code>Choose Country</code>, <code>Street Address</code></small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-id"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-id">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-id">Unique Field ID: *</label></label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-id">';form+='<td colspan="2">';form+='<input type="text" property="id" maxlength="25" autocomplete="off" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-id" value="'+esc_attr(field.id)+'" /><br />';form+="<small>Examples: <code>country_code</code>, <code>street_address</code></small><br />";form+='<small>e.g. <code>[s2Get user_field="country_code" /]</code></small>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-required"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-required">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-required">Field Required: *</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-required">';form+='<td colspan="2">';form+='<select property="required" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-required">';form+='<option value="yes"'+((field.required==="yes")?' selected="selected"':"")+'">Yes (required)</option>';form+='<option value="no"'+((field.required==="no")?' selected="selected"':"")+'">No (optional)</option>';form+="</select><br />";form+='<small>If <code>yes</code>, only Users/Members will be "required" to enter this field.</small><br />';form+="<small>* Administrators are exempt from this requirement.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-deflt"'+((field.type.match(/^(text|textarea)$/))?"":' style="display:none;"')+'><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-deflt"'+((field.type.match(/^(text|textarea)$/))?"":' style="display:none;"')+">";form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-deflt">Default Text Value: (optional)</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-deflt"'+((field.type.match(/^(text|textarea)$/))?"":' style="display:none;"')+">";form+='<td colspan="2">';form+='<textarea property="deflt" wrap="off" spellcheck="false" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-deflt" rows="1">'+esc_html(field.deflt)+"</textarea><br />";form+="<small>Default value before user input is received.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-options"'+((field.type.match(/^(select|selects|checkboxes|radios)$/))?"":' style="display:none;"')+'><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-options"'+((field.type.match(/^(select|selects|checkboxes|radios)$/))?"":' style="display:none;"')+">";form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-options">Option Configuration File: * (one option per line)</label><br />';form+="<small>Use a pipe <code>|</code> delimited format: <code>option value|option label</code></small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-options"'+((field.type.match(/^(select|selects|checkboxes|radios)$/))?"":' style="display:none;"')+">";form+='<td colspan="2">';form+='<textarea property="options" wrap="off" spellcheck="false" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-options" rows="3">'+esc_html(field.options)+"</textarea><br />";form+="Here is a quick example:<br />";form+="<small>You can also specify a <em>default</em> option:</small><br />";form+="<code>US|United States|default</code><br />";form+="<code>CA|Canada</code><br />";form+="<code>VI|Virgin Islands (U.S.)</code>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-expected"'+((field.type.match(/^(text|textarea)$/))?"":' style="display:none;"')+'><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-expected"'+((field.type.match(/^(text|textarea)$/))?"":' style="display:none;"')+">";form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-expected">Expected Format: *</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-expected"'+((field.type.match(/^(text|textarea)$/))?"":' style="display:none;"')+">";form+='<td colspan="2">';form+='<select property="expected" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-expected">';form+='<option value=""'+((field.expected==="")?' selected="selected"':"")+'">Anything Goes</option>';form+='<option disabled="disabled"></option>';form+='<optgroup label="Specific Input Types">';form+='<option value="numeric-wp-commas"'+((field.expected==="numeric-wp-commas")?' selected="selected"':"")+'">Numeric (with or without decimals, commas allowed)</option>';form+='<option value="numeric"'+((field.expected==="numeric")?' selected="selected"':"")+'">Numeric (with or without decimals, no commas)</option>';form+='<option value="integer"'+((field.expected==="integer")?' selected="selected"':"")+'">Integer (whole number, without any decimals)</option>';form+='<option value="integer-gt-0"'+((field.expected==="integer-gt-0")?' selected="selected"':"")+'">Integer > 0 (whole number, no decimals, greater than 0)</option>';form+='<option value="float"'+((field.expected==="float")?' selected="selected"':"")+'">Float (floating point number, decimals required)</option>';form+='<option value="float-gt-0"'+((field.expected==="float-gt-0")?' selected="selected"':"")+'">Float > 0 (floating point number, decimals required, greater than 0)</option>';form+='<option value="date"'+((field.expected==="date")?' selected="selected"':"")+'">Date (required date format: dd/mm/yyyy)</option>';form+='<option value="email"'+((field.expected==="email")?' selected="selected"':"")+'">Email (require valid email)</option>';form+='<option value="url"'+((field.expected==="url")?' selected="selected"':"")+'">Full URL (starting with http or https)</option>';form+='<option value="domain"'+((field.expected==="domain")?' selected="selected"':"")+'">Domain Name (domain name only, without http)</option>';form+='<option value="phone"'+((field.expected==="phone")?' selected="selected"':"")+'">Phone # (10 digits w/possible hyphens,spaces,brackets)</option>';form+='<option value="uszip"'+((field.expected==="uszip")?' selected="selected"':"")+'">US Zipcode (5-9 digits w/possible hyphen)</option>';form+='<option value="cazip"'+((field.expected==="cazip")?' selected="selected"':"")+'">Canadian Zipcode (6 alpha-numerics w/possible space)</option>';form+='<option value="uczip"'+((field.expected==="uczip")?' selected="selected"':"")+'">US/Canadian Zipcode (either a US or Canadian zipcode)</option>';form+="</optgroup>";form+='<option disabled="disabled"></option>';form+='<optgroup label="Any Character Combination">';for(i=1;i<=25;i++){form+='<option value="any-'+i+'"'+((field.expected==="any-"+i)?' selected="selected"':"")+'">Any Character Combination ( '+i+" character minimum )</option>";form+='<option value="any-'+i+'-e"'+((field.expected==="any-"+i+"-e")?' selected="selected"':"")+'">Any Character Combination ( exactly '+i+" character"+((i>1)?"s":"")+" )</option>"}form+="</optgroup>";form+='<option disabled="disabled"></option>';form+='<optgroup label="Alphanumerics, Spaces &amp; Punctuation Only">';for(i=1;i<=25;i++){form+='<option value="alphanumerics-spaces-punctuation-'+i+'"'+((field.expected==="alphanumerics-spaces-punctuation-"+i)?' selected="selected"':"")+'">Alphanumerics, Spaces &amp; Punctuation ( '+i+" character minimum )</option>";form+='<option value="alphanumerics-spaces-punctuation-'+i+'-e"'+((field.expected==="alphanumerics-spaces-punctuation-"+i+"-e")?' selected="selected"':"")+'">Alphanumerics, Spaces &amp; Punctuation ( exactly '+i+" character"+((i>1)?"s":"")+" )</option>"}form+="</optgroup>";form+='<option disabled="disabled"></option>';form+='<optgroup label="Alphanumerics &amp; Spaces Only">';for(i=1;i<=25;i++){form+='<option value="alphanumerics-spaces-'+i+'"'+((field.expected==="alphanumerics-spaces-"+i)?' selected="selected"':"")+'">Alphanumerics &amp; Spaces ( '+i+" character minimum )</option>";form+='<option value="alphanumerics-spaces-'+i+'-e"'+((field.expected==="alphanumerics-spaces-"+i+"-e")?' selected="selected"':"")+'">Alphanumerics &amp; Spaces ( exactly '+i+" character"+((i>1)?"s":"")+" )</option>"}form+="</optgroup>";form+='<option disabled="disabled"></option>';form+='<optgroup label="Alphanumerics &amp; Punctuation Only">';for(i=1;i<=25;i++){form+='<option value="alphanumerics-punctuation-'+i+'"'+((field.expected==="alphanumerics-punctuation-"+i)?' selected="selected"':"")+'">Alphanumerics &amp; Punctuation ( '+i+" character minimum )</option>";form+='<option value="alphanumerics-punctuation-'+i+'-e"'+((field.expected==="alphanumerics-punctuation-"+i+"-e")?' selected="selected"':"")+'">Alphanumerics &amp; Punctuation ( exactly '+i+" character"+((i>1)?"s":"")+" )</option>"}form+="</optgroup>";form+='<option disabled="disabled"></option>';form+='<optgroup label="Alphanumerics Only">';for(i=1;i<=25;i++){form+='<option value="alphanumerics-'+i+'"'+((field.expected==="alphanumerics-"+i)?' selected="selected"':"")+'">Alphanumerics ( '+i+" character minimum )</option>";form+='<option value="alphanumerics-'+i+'-e"'+((field.expected==="alphanumerics-"+i+"-e")?' selected="selected"':"")+'">Alphanumerics ( exactly '+i+" character"+((i>1)?"s":"")+" )</option>"}form+="</optgroup>";form+='<option disabled="disabled"></option>';form+='<optgroup label="Alphabetics Only">';for(i=1;i<=25;i++){form+='<option value="alphabetics-'+i+'"'+((field.expected==="alphabetics-"+i)?' selected="selected"':"")+'">Alphabetics ( '+i+" character minimum )</option>";form+='<option value="alphabetics-'+i+'-e"'+((field.expected==="alphabetics-"+i+"-e")?' selected="selected"':"")+'">Alphabetics ( exactly '+i+" character"+((i>1)?"s":"")+" )</option>"}form+="</optgroup>";form+='<option disabled="disabled"></option>';form+='<optgroup label="Numeric Digits Only">';for(i=1;i<=25;i++){form+='<option value="numerics-'+i+'"'+((field.expected==="numerics-"+i)?' selected="selected"':"")+'">Numeric Digits ( '+i+" digit minimum )</option>";form+='<option value="numerics-'+i+'-e"'+((field.expected==="numerics-"+i+"-e")?' selected="selected"':"")+'">Numeric Digits ( exactly '+i+" digit"+((i>1)?"s":"")+" )</option>"}form+="</optgroup>";form+="</select><br />";form+="<small>Only Users/Members will be required to meet this criteria.</small><br />";form+="<small>* Administrators are exempt from this.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-levels"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-levels">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-levels">Applicable Membership Levels: *</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-levels">';form+='<td colspan="2">';form+='<input type="text" property="levels" autocomplete="off" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-levels" value="'+esc_attr(field.levels)+'" /><br />';form+="<small>Please use comma-delimited Level #'s: <code>0,1,2,3,4</code> or type: <code>all</code>.</small><br />";form+="<small>This allows you to enable this field - only at specific Membership Levels.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-editable"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-editable">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-editable">Allow Profile Edits: *</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-editable">';form+='<td colspan="2">';form+='<select property="editable" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-editable">';form+='<option value="yes"'+((field.editable==="yes")?' selected="selected"':"")+'">Yes (editable)</option>';form+='<option value="no"'+((field.editable==="no")?' selected="selected"':"")+'">No (uneditable after registration)</option>';form+='<option value="no-invisible"'+((field.editable==="no-invisible")?' selected="selected"':"")+'">No (uneditable &amp; totally invisible after registration)</option>';form+='<option value="no-always-invisible"'+((field.editable==="no-always-invisible")?' selected="selected"':"")+'">No (uneditable &amp; totally invisible, both during &amp; after registration)</option>';form+='<option value="yes-invisible"'+((field.editable==="yes-invisible")?' selected="selected"':"")+'">Yes (editable after registration / invisible during registration)</option>';form+="</select><br />";form+="<small>If <code>No</code>, this field will be un-editable after registration.</small><br />";form+="<small>* Administrators are exempt from this.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-classes"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-classes">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-classes">CSS Classes: (optional)</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-classes">';form+='<td colspan="2">';form+='<input type="text" property="classes" autocomplete="off" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-classes" value="'+esc_attr(field.classes)+'" /><br />';form+="<small>Example: <code>my-style-1 my-style-2</code></small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-styles"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-styles">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-styles">CSS Styles: (optional)</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-styles">';form+='<td colspan="2">';form+='<input type="text" property="styles" autocomplete="off" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-styles" value="'+esc_attr(field.styles)+'" /><br />';form+="<small>Example: <code>color:#000000; background:#FFFFFF;</code></small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-attrs"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-attrs">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-attrs">Other Attributes: (optional)</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-attrs">';form+='<td colspan="2">';form+='<input type="text" property="attrs" autocomplete="off" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-attrs" value="'+esc_attr(field.attrs)+'" /><br />';form+='<small>Example: <code>onkeyup="" onblur=""</code></small>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-buttons"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-buttons">';form+='<td align="left">';form+='<input type="button" value="Cancel" onclick="ws_plugin__s2member_customRegFieldCancel();" />';form+="</td>";form+='<td align="right">';form+='<input type="button" value="'+((editing)?"Update This Field":"Create Registration Field")+'" onclick="'+((editing)?"ws_plugin__s2member_customRegFieldUpdate("+index+");":"ws_plugin__s2member_customRegFieldCreate();")+'" />';form+="</td>";form+="</tr>";form+="</tbody>";form+="</table>";form+="<div>";$("body").append(form);tb_show(((editing)?"Editing Registration/Profile Field":"New Custom Registration/Profile Field"),"#TB_inline?inlineId=ws-plugin--s2member-custom-reg-field-configuration-thickbox-tools-form");$("table#ws-plugin--s2member-custom-reg-field-configuration-tools-form").show()}$tools.html(html)};var buildTable=function(){var l=fields.length,i=0,html="",eo="o";html+="<tbody>";html+="<tr>";html+="<th>Order</th>";html+="<th>Field Type</th>";html+="<th>Unique ID</th>";html+="<th>Required</th>";html+="<th>Levels</th>";html+="<th>- Tools -</th>";html+="</tr>";if(fields.length>0){for(i=0;i<fields.length;i++){html+='<tr class="'+esc_attr((eo=(eo==="o")?"e":"o"))+((fields[i].section==="yes")?" s":"")+" ws-plugin--s2member-custom-reg-field-configuration-table-row-"+i+'">';html+='<td nowrap="nowrap"><a class="ws-plugin--s2member-custom-reg-field-configuration-move-up" href="#" onclick="ws_plugin__s2member_customRegFieldMoveUp('+i+'); return false;"></a><a class="ws-plugin--s2member-custom-reg-field-configuration-move-down" href="#" onclick="ws_plugin__s2member_customRegFieldMoveDown('+i+'); return false;"></a></td>';html+='<td nowrap="nowrap">'+esc_html(fieldTypeDesc(fields[i].type))+"</td>";html+='<td nowrap="nowrap">'+esc_html(fields[i].id)+"</td>";html+='<td nowrap="nowrap">'+esc_html(fields[i].required)+"</td>";html+='<td nowrap="nowrap">'+esc_html(fields[i].levels)+"</td>";html+='<td nowrap="nowrap"><a class="ws-plugin--s2member-custom-reg-field-configuration-edit" href="#" onclick="ws_plugin__s2member_customRegFieldEdit('+i+'); return false;"></a><a class="ws-plugin--s2member-custom-reg-field-configuration-delete" href="#" onclick="ws_plugin__s2member_customRegFieldDelete('+i+'); return false;"></a></td>';html+="</tr>"}}else{html+="<tr>";html+='<td colspan="6">No Custom Fields are configured.</td>';html+="</tr>"}html+="</tbody>";$table.html(html)};buildTools(),buildTable()})()}}if(location.href.match(/page\=ws-plugin--s2member-res-ops/)){$("input#ws-plugin--s2member-brute-force-restrictions-reset-button").click(function(){var $this=$(this);$this.val("one moment please ...");$.post(ajaxurl,{action:"ws_plugin__s2member_delete_reset_all_ip_restrictions_via_ajax",ws_plugin__s2member_delete_reset_all_ip_restrictions_via_ajax:'<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (wp_create_nonce ("ws-plugin--s2member-delete-reset-all-ip-restrictions-via-ajax")); ?>'},function(response){alert("s2Member's Brute Force Restriction Logs have all been reset."),$this.val("Reset Brute Force Logs")});return false});$("input#ws-plugin--s2member-ip-restrictions-reset-button").click(function(){var $this=$(this);$this.val("one moment please ...");$.post(ajaxurl,{action:"ws_plugin__s2member_delete_reset_all_ip_restrictions_via_ajax",ws_plugin__s2member_delete_reset_all_ip_restrictions_via_ajax:'<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (wp_create_nonce ("ws-plugin--s2member-delete-reset-all-ip-restrictions-via-ajax")); ?>'},function(response){alert("s2Member's IP Restriction Logs have all been reset."),$this.val("Reset IP Restriction Logs")});return false});$('div.ws-plugin--s2member-query-level-access-section input[type="checkbox"][name="ws_plugin__s2member_filter_wp_query[]"]').change(function(){var thisChange=$(this).val();$('div.ws-plugin--s2member-query-level-access-section input[type="checkbox"][name="ws_plugin__s2member_filter_wp_query[]"]').each(function(){var $this=$(this),val=$this.val(),checkboxes='input[type="checkbox"]';if(val==="all"&&this.checked){$this.nextAll(checkboxes).attr({checked:"checked",disabled:"disabled"})}else{if(val==="all"&&!this.checked){$this.nextAll(checkboxes).removeAttr("disabled");(thisChange==="all")?$this.nextAll(checkboxes).removeAttr("checked"):null}}})}).last().trigger("change")}if(location.href.match(/page\=ws-plugin--s2member-down-ops/)){var updateCloudFrontPrivateKey=function(){var $hiddenPrivateKey=$("input#ws-plugin--s2member-amazon-cf-files-private-key");var $visiblePrivateKeyEntry=$("textarea#ws-plugin--s2member-amazon-cf-files-private-key-entry");var hiddenPrivateKeyValue=$.trim($hiddenPrivateKey.val()),visiblePrivateKeyEntryValue=$.trim($visiblePrivateKeyEntry.val());if((hiddenPrivateKeyValue&&!visiblePrivateKeyEntryValue)||visiblePrivateKeyEntryValue.match(/[^\r\n\u25CF]/)){$hiddenPrivateKey.val(visiblePrivateKeyEntryValue),$visiblePrivateKeyEntry.val(visiblePrivateKeyEntryValue.replace(/[^\r\n]/g,String.fromCharCode(9679)))}};$("form#ws-plugin--s2member-options-form").submit(updateCloudFrontPrivateKey);$("textarea#ws-plugin--s2member-amazon-cf-files-private-key-entry").change(updateCloudFrontPrivateKey).trigger("change");var updateCloudFrontDistroCfgs=function(){var $hiddenPrivateKey=$("input#ws-plugin--s2member-amazon-cf-files-private-key");var $visiblePrivateKeyId=$("input#ws-plugin--s2member-amazon-cf-files-private-key-id");var $autoConfigDistros=$("input#ws-plugin--s2member-amazon-cf-files-auto-configure-distros");var $autoConfigDistrosStatus=$("input#ws-plugin--s2member-amazon-cf-files-distros-auto-config-status");var autoConfigDistrosStatusValue=$.trim($autoConfigDistrosStatus.val());var hiddenPrivateKeyValue=$.trim($hiddenPrivateKey.val()),visiblePrivateKeyIdValue=$.trim($visiblePrivateKeyId.val());var hiddenPrivateKeyPrevConfigValue=$.trim($hiddenPrivateKey.attr("data-s-prev-config-value")),visiblePrivateKeyIdPrevConfigValue=$.trim($visiblePrivateKeyId.attr("data-s-prev-config-value"));if(autoConfigDistrosStatusValue==="configured"&&((visiblePrivateKeyIdPrevConfigValue&&visiblePrivateKeyIdValue!==visiblePrivateKeyIdPrevConfigValue)||(hiddenPrivateKeyPrevConfigValue&&hiddenPrivateKeyValue!==hiddenPrivateKeyPrevConfigValue))){alert("s2Member will need to delete and re-configure your Amazon® CloudFront distributions if you change this. When you're done editing, click (Save All Changes) below.");$autoConfigDistros.attr("checked","checked")}else{if(autoConfigDistrosStatusValue!=="configured"&&visiblePrivateKeyIdValue&&hiddenPrivateKeyValue){alert("s2Member will need to auto-configure your Amazon® CloudFront distributions for you. When you're done editing, click (Save All Changes) below.");$autoConfigDistros.attr("checked","checked")}}};$("input#ws-plugin--s2member-amazon-cf-files-private-key-id").change(updateCloudFrontDistroCfgs);$("textarea#ws-plugin--s2member-amazon-cf-files-private-key-entry").change(updateCloudFrontDistroCfgs);$("input#ws-plugin--s2member-amazon-cf-files-auto-configure-distros-w-cnames").change(function(){var $this=$(this),thisChecked=(this.checked)?true:false;var $autoConfigDistros=$("input#ws-plugin--s2member-amazon-cf-files-auto-configure-distros");var $autoConfigDistroCnames=$("div#ws-plugin--s2member-amazon-cf-files-auto-configure-distro-cnames");(thisChecked)?$autoConfigDistroCnames.show():$autoConfigDistroCnames.hide();(thisChecked)?$autoConfigDistros.attr("checked","checked"):null}).trigger("change")}if(location.href.match(/page\=ws-plugin--s2member-paypal-ops/)){$("select#ws-plugin--s2member-auto-eot-system-enabled").change(function(){var $this=$(this),val=$this.val();var $viaCron=$("p#ws-plugin--s2member-auto-eot-system-enabled-via-cron");if(val==2){$viaCron.show()}else{$viaCron.hide()}})}if(location.href.match(/page\=ws-plugin--s2member-paypal-buttons/)){$("div.ws-menu-page select[id]").filter(function(){return this.id.match(/^ws-plugin--s2member-(level[1-9][0-9]*|modification)-term$/)}).change(function(){var button=this.id.replace(/^ws-plugin--s2member-(.+?)-term$/g,"$1");var trialDisabled=($(this).val().split("-")[2].replace(/[^0-1BN]/g,"")==="BN")?1:0;$("p#ws-plugin--s2member-"+button+"-trial-line").css("display",(trialDisabled?"none":""));$("span#ws-plugin--s2member-"+button+"-trial-then").css("display",(trialDisabled?"none":""));$("span#ws-plugin--s2member-"+button+"-20p-rule").css("display",(trialDisabled?"none":""));(trialDisabled)?$("input#ws-plugin--s2member-"+button+"-trial-period").val(0):null;(trialDisabled)?$("input#ws-plugin--s2member-"+button+"-trial-amount").val("0.00"):null});$("div.ws-menu-page input[id]").filter(function(){return this.id.match(/^ws-plugin--s2member-(level[1-9][0-9]*|modification|ccap)-ccaps$/)}).keyup(function(){var value=this.value.replace(/^(-all|-al|-a|-)[;,]*/gi,""),_all=(this.value.match(/^(-all|-al|-a|-)[;,]*/i))?"-all,":"";if(value.match(/[^a-z_0-9,]/)){this.value=_all+$.trim($.trim(value).replace(/[ \-]/g,"_").replace(/[^a-z_0-9,]/gi,"").toLowerCase())}});ws_plugin__s2member_paypalButtonGenerate=function(button){var shortCodeTemplate='[s2Member-PayPal-Button %%attrs%% image="default" output="button" /]',shortCodeTemplateAttrs="",labels={};eval("<?php echo c_ws_plugin__s2member_utils_strings::esc_dq($labels); ?>");var shortCode=$("input#ws-plugin--s2member-"+button+"-shortcode");var code=$("textarea#ws-plugin--s2member-"+button+"-button");var modLevel=$("select#ws-plugin--s2member-modification-level");var level=(button==="modification")?modLevel.val().split(":",2)[1]:button.replace(/^level/,"");var label=labels["level"+level].replace(/"/g,"");var desc=$.trim($("input#ws-plugin--s2member-"+button+"-desc").val().replace(/"/g,""));var trialAmount=$("input#ws-plugin--s2member-"+button+"-trial-amount").val().replace(/[^0-9\.]/g,"");var trialPeriod=$("input#ws-plugin--s2member-"+button+"-trial-period").val().replace(/[^0-9]/g,"");var trialTerm=$("select#ws-plugin--s2member-"+button+"-trial-term").val().replace(/[^A-Z]/g,"");var regAmount=$("input#ws-plugin--s2member-"+button+"-amount").val().replace(/[^0-9\.]/g,"");var regPeriod=$("select#ws-plugin--s2member-"+button+"-term").val().split("-")[0].replace(/[^0-9]/g,"");var regTerm=$("select#ws-plugin--s2member-"+button+"-term").val().split("-")[1].replace(/[^A-Z]/g,"");var regRecur=$("select#ws-plugin--s2member-"+button+"-term").val().split("-")[2].replace(/[^0-1BN]/g,"");var regRecurTimes="",regRecurRetry="1";var localeCode="",digital="0",noShipping="1";var pageStyle=$.trim($("input#ws-plugin--s2member-"+button+"-page-style").val().replace(/"/g,""));var currencyCode=$("select#ws-plugin--s2member-"+button+"-currency").val().replace(/[^A-Z]/g,"");var cCaps=$.trim($.trim($("input#ws-plugin--s2member-"+button+"-ccaps").val()).replace(/^(-all|-al|-a|-)[;,]*/gi,"").replace(/[ \-]/g,"_").replace(/[^a-z_0-9,]/gi,"").toLowerCase());cCaps=($.trim($("input#ws-plugin--s2member-"+button+"-ccaps").val()).match(/^(-all|-al|-a|-)[;,]*/i))?((cCaps)?"-all,":"-all")+cCaps.toLowerCase():cCaps.toLowerCase();trialPeriod=(regRecur==="BN")?"0":trialPeriod;trialAmount=(!trialAmount||isNaN(trialAmount)||trialAmount<0.01||trialPeriod<=0)?"0":trialAmount;var levelCcapsPer=(regRecur==="BN"&&regTerm!=="L")?level+":"+cCaps+":"+regPeriod+" "+regTerm:level+":"+cCaps;levelCcapsPer=levelCcapsPer.replace(/\:+$/g,"");if(trialAmount!=="0"&&(isNaN(trialAmount)||trialAmount<0)){alert("— Oops, a slight problem: —\n\nWhen provided, Trial Amount must be >= 0.00");return false}else{if(trialAmount!=="0"&&trialAmount>10000&&currencyCode.toUpperCase()==="USD"){alert("— Oops, a slight problem: —\n\nMaximum Trial Amount is: 10000.00");return false}else{if(trialTerm==="D"&&trialPeriod>90){alert("— Oops, a slight problem: —\n\nMaximum Trial Days is: 90.\nIf you want to offer more than 90 days, please choose Weeks or Months from the drop-down.");return false}else{if(trialTerm==="W"&&trialPeriod>52){alert("— Oops, a slight problem: —\n\nMaximum Trial Weeks is: 52.\nIf you want to offer more than 52 weeks, please choose Months from the drop-down.");return false}else{if(trialTerm==="M"&&trialPeriod>24){alert("— Oops, a slight problem: —\n\nMaximum Trial Months is: 24.\nIf you want to offer more than 24 months, please choose Years from the drop-down.");return false}else{if(trialTerm==="Y"&&trialPeriod>5){alert("— Oops, a slight problem: —\n\nMax Trial Period Years is: 5.");return false}else{if(!regAmount||isNaN(regAmount)||regAmount<0.01){alert("— Oops, a slight problem: —\n\nAmount must be >= 0.01");return false}else{if(regAmount>10000&&currencyCode.toUpperCase()==="USD"){alert("— Oops, a slight problem: —\n\nMaximum Amount is: 10000.00");return false}else{if(!desc){alert("— Oops, a slight problem: —\n\nPlease type a Description for this Button.");return false}}}}}}}}}code.html(code.val().replace(/ \<\!--(\<input type\="hidden" name\="(amount|src|srt|sra|a1|p1|t1|a3|p3|t3)" value\="(.*?)" \/\>)--\>/g," $1"));(parseInt(trialPeriod)<=0)?code.html(code.val().replace(/ (\<input type\="hidden" name\="(a1|p1|t1)" value\="(.*?)" \/\>)/g," <!--$1-->")):null;(regRecur==="BN")?code.html(code.val().replace(/ (\<input type\="hidden" name\="cmd" value\=")(.*?)(" \/\>)/g," $1_xclick$3")):null;(regRecur==="BN")?code.html(code.val().replace(/ (\<input type\="hidden" name\="(src|srt|sra|a1|p1|t1|a3|p3|t3)" value\="(.*?)" \/\>)/g," <!--$1-->")):null;(regRecur!=="BN")?code.html(code.val().replace(/ (\<input type\="hidden" name\="cmd" value\=")(.*?)(" \/\>)/g," $1_xclick-subscriptions$3")):null;(regRecur!=="BN")?code.html(code.val().replace(/ (\<input type\="hidden" name\="amount" value\="(.*?)" \/\>)/g," <!--$1-->")):null;shortCodeTemplateAttrs+=(button==="modification")?'modify="1" ':"";shortCodeTemplateAttrs+='level="'+esc_attr(level)+'" ccaps="'+esc_attr(cCaps)+'" desc="'+esc_attr(desc)+'" ps="'+esc_attr(pageStyle)+'" lc="'+esc_attr(localeCode)+'" cc="'+esc_attr(currencyCode)+'" dg="'+esc_attr(digital)+'" ns="'+esc_attr(noShipping)+'" custom="<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"])); ?>"';shortCodeTemplateAttrs+=' ta="'+esc_attr(trialAmount)+'" tp="'+esc_attr(trialPeriod)+'" tt="'+esc_attr(trialTerm)+'" ra="'+esc_attr(regAmount)+'" rp="'+esc_attr(regPeriod)+'" rt="'+esc_attr(regTerm)+'" rr="'+esc_attr(regRecur)+'" rrt="'+esc_attr(regRecurTimes)+'" rra="'+esc_attr(regRecurRetry)+'"';shortCode.val(shortCodeTemplate.replace(/%%attrs%%/,shortCodeTemplateAttrs));code.html(code.val().replace(/ name\="lc" value\="(.*?)"/,' name="lc" value="'+esc_attr(localeCode)+'"'));code.html(code.val().replace(/ name\="no_shipping" value\="(.*?)"/,' name="no_shipping" value="'+esc_attr(noShipping)+'"'));code.html(code.val().replace(/ name\="item_name" value\="(.*?)"/,' name="item_name" value="'+esc_attr(desc)+'"'));code.html(code.val().replace(/ name\="item_number" value\="(.*?)"/,' name="item_number" value="'+esc_attr(levelCcapsPer)+'"'));code.html(code.val().replace(/ name\="page_style" value\="(.*?)"/,' name="page_style" value="'+esc_attr(pageStyle)+'"'));code.html(code.val().replace(/ name\="currency_code" value\="(.*?)"/,' name="currency_code" value="'+esc_attr(currencyCode)+'"'));code.html(code.val().replace(/ name\="custom" value\="(.*?)"/,' name="custom" value="<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"])); ?>"'));code.html(code.val().replace(/ name\="modify" value\="(.*?)"/,' name="modify" value="'+((button==="modification")?"1":"0")+'"'));code.html(code.val().replace(/ name\="amount" value\="(.*?)"/,' name="amount" value="'+esc_attr(regAmount)+'"'));code.html(code.val().replace(/ name\="src" value\="(.*?)"/,' name="src" value="'+esc_attr(regRecur)+'"'));code.html(code.val().replace(/ name\="srt" value\="(.*?)"/,' name="srt" value="'+esc_attr(regRecurTimes)+'"'));code.html(code.val().replace(/ name\="sra" value\="(.*?)"/,' name="sra" value="'+esc_attr(regRecurRetry)+'"'));code.html(code.val().replace(/ name\="a1" value\="(.*?)"/,' name="a1" value="'+esc_attr(trialAmount)+'"'));code.html(code.val().replace(/ name\="p1" value\="(.*?)"/,' name="p1" value="'+esc_attr(trialPeriod)+'"'));code.html(code.val().replace(/ name\="t1" value\="(.*?)"/,' name="t1" value="'+esc_attr(trialTerm)+'"'));code.html(code.val().replace(/ name\="a3" value\="(.*?)"/,' name="a3" value="'+esc_attr(regAmount)+'"'));code.html(code.val().replace(/ name\="p3" value\="(.*?)"/,' name="p3" value="'+esc_attr(regPeriod)+'"'));code.html(code.val().replace(/ name\="t3" value\="(.*?)"/,' name="t3" value="'+esc_attr(regTerm)+'"'));$("div#ws-plugin--s2member-"+button+"-button-prev").html(code.val().replace(/\<form/,'<form target="_blank"').replace(/\<\?php echo S2MEMBER_VALUE_FOR_PP_INV\(\); \?\>/g,Math.round(new Date().getTime())+'~<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["REMOTE_ADDR"])); ?>').replace(/\<\?php echo S2MEMBER_CURRENT_USER_VALUE_FOR_PP_(ON0|OS0|ON1|OS1); \?\>/g,""));(button==="modification")?alert("Your Modification Button has been generated.\nPlease copy/paste the Shortcode into your Login Welcome Page, or wherever you feel it would be most appropriate.\n\n* Remember, Modification Buttons should be displayed to existing Users/Members, and they should be logged-in, BEFORE clicking this Button."):alert("Your Button has been generated.\nPlease copy/paste the Shortcode Format into your Membership Options Page.");shortCode.each(function(){this.focus(),this.select()});return false};ws_plugin__s2member_paypalCcapButtonGenerate=function(){var shortCodeTemplate='[s2Member-PayPal-Button %%attrs%% image="default" output="button" /]',shortCodeTemplateAttrs="";var shortCode=$("input#ws-plugin--s2member-ccap-shortcode");var code=$("textarea#ws-plugin--s2member-ccap-button");var desc=$.trim($("input#ws-plugin--s2member-ccap-desc").val().replace(/"/g,""));var regAmount=$("input#ws-plugin--s2member-ccap-amount").val().replace(/[^0-9\.]/g,"");var regPeriod=$("select#ws-plugin--s2member-ccap-term").val().split("-")[0].replace(/[^0-9]/g,"");var regTerm=$("select#ws-plugin--s2member-ccap-term").val().split("-")[1].replace(/[^A-Z]/g,"");var regRecur=$("select#ws-plugin--s2member-ccap-term").val().split("-")[2].replace(/[^0-1BN]/g,"");var localeCode="",digital="0",noShipping="1";var pageStyle=$.trim($("input#ws-plugin--s2member-ccap-page-style").val().replace(/"/g,""));var currencyCode=$("select#ws-plugin--s2member-ccap-currency").val().replace(/[^A-Z]/g,"");var cCaps=$.trim($.trim($("input#ws-plugin--s2member-ccap-ccaps").val()).replace(/^(-all|-al|-a|-)[;,]*/gi,"").replace(/[ \-]/g,"_").replace(/[^a-z_0-9,]/gi,"").toLowerCase());cCaps=($.trim($("input#ws-plugin--s2member-ccap-ccaps").val()).match(/^(-all|-al|-a|-)[;,]*/i))?((cCaps)?"-all,":"-all")+cCaps.toLowerCase():cCaps.toLowerCase();var levelCcapsPer=(regRecur==="BN"&&regTerm!=="L")?"*:"+cCaps+":"+regPeriod+" "+regTerm:"*:"+cCaps;levelCcapsPer=levelCcapsPer.replace(/\:+$/g,"");if(!cCaps||cCaps==="-all"){alert("— Oops, a slight problem: —\n\nPlease provide at least one Custom Capability.");return false}else{if(!regAmount||isNaN(regAmount)||regAmount<0.01){alert("— Oops, a slight problem: —\n\nAmount must be >= 0.01");return false}else{if(regAmount>10000&&currencyCode.toUpperCase()==="USD"){alert("— Oops, a slight problem: —\n\nMaximum Amount is: 10000.00");return false}else{if(!desc){alert("— Oops, a slight problem: —\n\nPlease type a Description for this Button.");return false}}}}shortCodeTemplateAttrs+='level="*" ccaps="'+esc_attr(cCaps)+'" desc="'+esc_attr(desc)+'" ps="'+esc_attr(pageStyle)+'" lc="'+esc_attr(localeCode)+'" cc="'+esc_attr(currencyCode)+'" dg="'+esc_attr(digital)+'" ns="'+esc_attr(noShipping)+'"';shortCodeTemplateAttrs+=' custom="<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"])); ?>" ra="'+esc_attr(regAmount)+'" rp="'+esc_attr(regPeriod)+'" rt="'+esc_attr(regTerm)+'" rr="'+esc_attr(regRecur)+'"';shortCode.val(shortCodeTemplate.replace(/%%attrs%%/,shortCodeTemplateAttrs));code.html(code.val().replace(/ name\="lc" value\="(.*?)"/,' name="lc" value="'+esc_attr(localeCode)+'"'));code.html(code.val().replace(/ name\="no_shipping" value\="(.*?)"/,' name="no_shipping" value="'+esc_attr(noShipping)+'"'));code.html(code.val().replace(/ name\="item_name" value\="(.*?)"/,' name="item_name" value="'+esc_attr(desc)+'"'));code.html(code.val().replace(/ name\="item_number" value\="(.*?)"/,' name="item_number" value="'+esc_attr(levelCcapsPer)+'"'));code.html(code.val().replace(/ name\="page_style" value\="(.*?)"/,' name="page_style" value="'+esc_attr(pageStyle)+'"'));code.html(code.val().replace(/ name\="currency_code" value\="(.*?)"/,' name="currency_code" value="'+esc_attr(currencyCode)+'"'));code.html(code.val().replace(/ name\="custom" value\="(.*?)"/,' name="custom" value="<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"])); ?>"'));code.html(code.val().replace(/ name\="amount" value\="(.*?)"/,' name="amount" value="'+esc_attr(regAmount)+'"'));$("div#ws-plugin--s2member-ccap-button-prev").html(code.val().replace(/\<form/,'<form target="_blank"').replace(/\<\?php echo S2MEMBER_VALUE_FOR_PP_INV\(\); \?\>/g,Math.round(new Date().getTime())+'~<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["REMOTE_ADDR"])); ?>').replace(/\<\?php echo S2MEMBER_CURRENT_USER_VALUE_FOR_PP_(ON0|OS0|ON1|OS1); \?\>/g,""));alert("Your Button has been generated.\nPlease copy/paste the Shortcode into your Login Welcome Page, or wherever you feel it would be most appropriate.\n\n* Remember, Independent Custom Capability Buttons should ONLY be displayed to existing Users/Members, and they MUST be logged-in, BEFORE clicking this Button.");shortCode.each(function(){this.focus(),this.select()});return false};ws_plugin__s2member_paypalSpButtonGenerate=function(){var shortCodeTemplate='[s2Member-PayPal-Button %%attrs%% image="default" output="button" /]',shortCodeTemplateAttrs="";var shortCode=$("input#ws-plugin--s2member-sp-shortcode");var code=$("textarea#ws-plugin--s2member-sp-button");var leading=$("select#ws-plugin--s2member-sp-leading-id").val().replace(/[^0-9]/g,"");var additionals=$("select#ws-plugin--s2member-sp-additional-ids").val()||[];var hours=$("select#ws-plugin--s2member-sp-hours").val().replace(/[^0-9]/g,"");var regAmount=$("input#ws-plugin--s2member-sp-amount").val().replace(/[^0-9\.]/g,"");var desc=$.trim($("input#ws-plugin--s2member-sp-desc").val().replace(/"/g,""));var localeCode="",digital="0",noShipping="1";var pageStyle=$.trim($("input#ws-plugin--s2member-sp-page-style").val().replace(/"/g,""));var currencyCode=$("select#ws-plugin--s2member-sp-currency").val().replace(/[^A-Z]/g,"");if(!leading){alert("— Oops, a slight problem: —\n\nPlease 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 -› Restriction Options -› Specific Post/Page Access.");return false}else{if(!regAmount||isNaN(regAmount)||regAmount<0.01){alert("— Oops, a slight problem: —\n\nAmount must be >= 0.01");return false}else{if(regAmount>10000&&currencyCode.toUpperCase()==="USD"){alert("— Oops, a slight problem: —\n\nMaximum Amount is: 10000.00");return false}else{if(!desc){alert("— Oops, a slight problem: —\n\nPlease type a Description for this Button.");return false}}}}for(var i=0,ids=leading;i<additionals.length;i++){if(additionals[i]&&additionals[i]!==leading){ids+=","+additionals[i]}}var spIdsHours="sp:"+ids+":"+hours;shortCodeTemplateAttrs+='sp="1" ids="'+esc_attr(ids)+'" exp="'+esc_attr(hours)+'" desc="'+esc_attr(desc)+'" ps="'+esc_attr(pageStyle)+'" lc="'+esc_attr(localeCode)+'" cc="'+esc_attr(currencyCode)+'" dg="'+esc_attr(digital)+'" ns="'+esc_attr(noShipping)+'"';shortCodeTemplateAttrs+=' custom="<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"])); ?>" ra="'+esc_attr(regAmount)+'"';shortCode.val(shortCodeTemplate.replace(/%%attrs%%/,shortCodeTemplateAttrs));code.html(code.val().replace(/ name\="lc" value\="(.*?)"/,' name="lc" value="'+esc_attr(localeCode)+'"'));code.html(code.val().replace(/ name\="no_shipping" value\="(.*?)"/,' name="no_shipping" value="'+esc_attr(noShipping)+'"'));code.html(code.val().replace(/ name\="item_name" value\="(.*?)"/,' name="item_name" value="'+esc_attr(desc)+'"'));code.html(code.val().replace(/ name\="item_number" value\="(.*?)"/,' name="item_number" value="'+esc_attr(spIdsHours)+'"'));code.html(code.val().replace(/ name\="page_style" value\="(.*?)"/,' name="page_style" value="'+esc_attr(pageStyle)+'"'));code.html(code.val().replace(/ name\="currency_code" value\="(.*?)"/,' name="currency_code" value="'+esc_attr(currencyCode)+'"'));code.html(code.val().replace(/ name\="custom" value\="(.*?)"/,' name="custom" value="<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"])); ?>"'));code.html(code.val().replace(/ name\="amount" value\="(.*?)"/,' name="amount" value="'+esc_attr(regAmount)+'"'));$("div#ws-plugin--s2member-sp-button-prev").html(code.val().replace(/\<form/,'<form target="_blank"').replace(/\<\?php echo S2MEMBER_VALUE_FOR_PP_INV\(\); \?\>/g,Math.round(new Date().getTime())+'~<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["REMOTE_ADDR"])); ?>').replace(/\<\?php echo S2MEMBER_CURRENT_USER_VALUE_FOR_PP_(ON0|OS0|ON1|OS1); \?\>/g,""));alert("Your Button has been generated.\nPlease copy/paste the Shortcode into your WordPress® Editor.");shortCode.each(function(){this.focus(),this.select()});return false};ws_plugin__s2member_paypalRegLinkGenerate=function(){var level=$("select#ws-plugin--s2member-reg-link-level").val().replace(/[^0-9]/g,"");var subscrID=$.trim($("input#ws-plugin--s2member-reg-link-subscr-id").val());var custom=$.trim($("input#ws-plugin--s2member-reg-link-custom").val());var cCaps=$.trim($.trim($("input#ws-plugin--s2member-reg-link-ccaps").val()).replace(/[ \-]/g,"_").replace(/[^a-z_0-9,]/gi,"").toLowerCase());var fixedTerm=$.trim($("input#ws-plugin--s2member-reg-link-fixed-term").val().replace(/[^A-Z 0-9]/gi,"").toUpperCase());var $link=$("p#ws-plugin--s2member-reg-link"),$loading=$("img#ws-plugin--s2member-reg-link-loading");var levelCcapsPer=(fixedTerm&&!fixedTerm.match(/L$/))?level+":"+cCaps+":"+fixedTerm:level+":"+cCaps;levelCcapsPer=levelCcapsPer.replace(/\:+$/g,"");if(!subscrID){alert("— Oops, a slight problem: —\n\nPaid Subscr. ID is a required value.");return false}else{if(!custom||custom.indexOf('<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq ($_SERVER["HTTP_HOST"]); ?>')!==0){alert("— Oops, a slight problem: —\n\nThe Custom Value MUST start with your domain name.");return false}else{if(fixedTerm&&!fixedTerm.match(/^[1-9]+ (D|W|M|Y|L)$/)){alert("— Oops, a slight problem: —\n\nThe Fixed Term Length is not formatted properly.");return false}}}$link.hide(),$loading.show(),$.post(ajaxurl,{action:"ws_plugin__s2member_reg_access_link_via_ajax",ws_plugin__s2member_reg_access_link_via_ajax:'<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (wp_create_nonce ("ws-plugin--s2member-reg-access-link-via-ajax")); ?>',s2member_reg_access_link_subscr_gateway:"paypal",s2member_reg_access_link_subscr_id:subscrID,s2member_reg_access_link_custom:custom,s2member_reg_access_link_item_number:levelCcapsPer},function(response){$link.show().html('<a href="'+esc_attr(response)+'" target="_blank" rel="external">'+esc_html(response)+"</a>"),$loading.hide()});return false};ws_plugin__s2member_paypalSpLinkGenerate=function(){var leading=$("select#ws-plugin--s2member-sp-link-leading-id").val().replace(/[^0-9]/g,"");var additionals=$("select#ws-plugin--s2member-sp-link-additional-ids").val()||[];var hours=$("select#ws-plugin--s2member-sp-link-hours").val().replace(/[^0-9]/g,"");var $link=$("p#ws-plugin--s2member-sp-link"),$loading=$("img#ws-plugin--s2member-sp-link-loading");if(!leading){alert("— Oops, a slight problem: —\n\nPlease 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 -› Restriction Options -› Specific Post/Page Access.");return false}for(var i=0,ids=leading;i<additionals.length;i++){if(additionals[i]&&additionals[i]!==leading){ids+=","+additionals[i]}}$link.hide(),$loading.show(),$.post(ajaxurl,{action:"ws_plugin__s2member_sp_access_link_via_ajax",ws_plugin__s2member_sp_access_link_via_ajax:'<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (wp_create_nonce ("ws-plugin--s2member-sp-access-link-via-ajax")); ?>',s2member_sp_access_link_ids:ids,s2member_sp_access_link_hours:hours},function(response){$link.show().html('<a href="'+esc_attr(response)+'" target="_blank" rel="external">'+esc_html(response)+"</a>"),$loading.hide()});return false}}if(location.href.match(/page\=ws-plugin--s2member-els-ops/)){$("select#ws-plugin--s2member-custom-reg-opt-in").change(function(){var $this=$(this),val=$this.val();var $rows=$("tr.ws-plugin--s2member-custom-reg-opt-in-label-row");var $prevImg=$("img.ws-plugin--s2member-custom-reg-opt-in-label-prev-img");if(val<=0){$rows.css("display","none"),$prevImg.attr("src",$prevImg.attr("src").replace(/\/checked\.png$/,"/unchecked.png"))}else{if(val==1){$rows.css("display",""),$prevImg.attr("src",$prevImg.attr("src").replace(/\/unchecked\.png$/,"/checked.png"))}else{if(val==2){$rows.css("display",""),$prevImg.attr("src",$prevImg.attr("src").replace(/\/checked\.png$/,"/unchecked.png"))}}}});$('div.ws-plugin--s2member-opt-out-section input[type="checkbox"][name="ws_plugin__s2member_custom_reg_auto_opt_outs[]"]').change(function(){var thisChange=$(this).val(),checkedIndexes=[];$('div.ws-plugin--s2member-opt-out-section input[type="checkbox"][name="ws_plugin__s2member_custom_reg_auto_opt_outs[]"]').each(function(){var $this=$(this),val=$this.val(),checkboxes='input[type="checkbox"]';if(val==="removal-deletion"&&this.checked){$this.nextAll(checkboxes).slice(0,2).attr({checked:"checked",disabled:"disabled"})}else{if(val==="removal-deletion"&&!this.checked){$this.nextAll(checkboxes).slice(0,2).removeAttr("disabled");(thisChange==="removal-deletion")?$this.nextAll(checkboxes).slice(0,2).removeAttr("checked"):null}else{if(val==="modification"&&this.checked){$this.nextAll(checkboxes).slice(0,3).attr({checked:"checked",disabled:"disabled"})}else{if(val==="modification"&&!this.checked){(thisChange==="modification")?$this.nextAll(checkboxes).slice(0,3).removeAttr("checked"):null;$this.nextAll(checkboxes).slice(0,3).removeAttr("disabled")}}}}}).each(function(index){(this.checked)?checkedIndexes.push(index):null});$("select#ws-plugin--s2member-custom-reg-auto-opt-out-transitions").removeAttr("disabled");if($.inArray(3,checkedIndexes)===-1&&$.inArray(4,checkedIndexes)===-1&&$.inArray(5,checkedIndexes)===-1&&$.inArray(6,checkedIndexes)===-1){$("select#ws-plugin--s2member-custom-reg-auto-opt-out-transitions").attr("disabled","disabled")}}).last().trigger("change")}});
1
+ jQuery(document).ready(function($){var esc_attr=esc_html=function(str){return String(str).replace(/"/g,"&quot;").replace(/\</g,"&lt;").replace(/\>/g,"&gt;")};if(location.href.match(/page\=ws-plugin--s2member/)){$("input.ws-plugin--s2member-update-roles-button, input.ws-plugin--s2member-reset-roles-button").click(function(){var $this=$(this);$this.val("one moment please ...");var levels='<?php echo (int)$GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]; ?>';var resetUpdate=($this.hasClass("ws-plugin--s2member-reset-roles-button"))?"Reset":"Update";$.post(ajaxurl,{action:"ws_plugin__s2member_update_roles_via_ajax",ws_plugin__s2member_update_roles_via_ajax:'<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (wp_create_nonce ("ws-plugin--s2member-update-roles-via-ajax")); ?>'},function(response){if(response==="1"){alert("s2Member's Roles/Capabilities "+((resetUpdate.toLowerCase()==="reset")?"have been successfully reset":"updated successfully")+".\nYour installation of s2Member has Membership Levels 0-"+levels+"."),$this.val(resetUpdate+" Roles/Capabilities")}else{if(response==="l"){alert("Sorry, your request failed.\ns2Member's Roles/Capabilities are locked by Filter:\nws_plugin__s2member_lock_roles_caps"),$this.val(resetUpdate+" Roles/Capabilities")}else{alert("Sorry, your request failed.\nAccess denied. Do you have the ability to `create_users`?"),$this.val(resetUpdate+" Roles/Capabilities")}}});return false})}if(location.href.match(/page\=ws-plugin--s2member-logs/)){$("input#ws-plugin--s2member-gateway-debug-logs-extensive-1").click(function(){var $this=$(this),thisChecked=(this.checked)?true:false;if(thisChecked){$("input#ws-plugin--s2member-gateway-debug-logs-1").attr("checked","checked")}});var $toggles=$("a.ws-plugin--s2member-log-file-viewport-toggle");$toggles.click(function(){$("textarea#ws-plugin--s2member-log-file-viewer").each(function(){var $viewer=$(this);if($viewer.attr("data-state")!=="expanded"){$viewer.css({height:($viewer.prop("scrollHeight")+50)+"px","overflow-y":"auto"});$toggles.html("&#8657; normalize viewport &#10073;");$viewer.attr("data-state","expanded")}else{$viewer.css({height:"auto","overflow-y":"scroll"});$toggles.html("&#8659; expand viewport &#8659;");$viewer.attr("data-state","scrolling")}});return false})}if(location.href.match(/page\=ws-plugin--s2member-mms-ops/)){$("select#ws-plugin--s2member-mms-registration-file").change(function(){if($(this).val()==="wp-signup"){var gv=$("select#ws-plugin--s2member-mms-registration-grants").val(),l0v=$("input#ws-plugin--s2member-mms-registration-blogs-level0").val();$("div#ws-plugin--s2member-mms-registration-support-package-details-wrapper").show(),$("div.ws-plugin--s2member-mms-registration-wp-login, table.ws-plugin--s2member-mms-registration-wp-login").hide(),$("div.ws-plugin--s2member-mms-registration-wp-signup, table.ws-plugin--s2member-mms-registration-wp-signup").show();$("div.ws-plugin--s2member-mms-registration-wp-signup-blogs-level0, table.ws-plugin--s2member-mms-registration-wp-signup-blogs-level0")[((gv==="all")?"show":"hide")]();$("input#ws-plugin--s2member-mms-registration-blogs-level0").val(((gv==="all")?((l0v>0)?l0v:"1"):"0"))}else{if($(this).val()==="wp-login"){var gv=$("select#ws-plugin--s2member-mms-registration-grants").val(),l0v=$("input#ws-plugin--s2member-mms-registration-blogs-level0").val();$("div#ws-plugin--s2member-mms-registration-support-package-details-wrapper").hide(),$("div.ws-plugin--s2member-mms-registration-wp-login, table.ws-plugin--s2member-mms-registration-wp-login").show(),$("div.ws-plugin--s2member-mms-registration-wp-signup, table.ws-plugin--s2member-mms-registration-wp-signup").hide();$("div.ws-plugin--s2member-mms-registration-wp-signup-blogs-level0, table.ws-plugin--s2member-mms-registration-wp-signup-blogs-level0").hide();$("input#ws-plugin--s2member-mms-registration-blogs-level0").val("0")}}}).trigger("change");$("select#ws-plugin--s2member-mms-registration-grants").change(function(){$("select#ws-plugin--s2member-mms-registration-file").trigger("change")})}if(location.href.match(/page\=ws-plugin--s2member-gen-ops/)){ws_plugin__s2member_generateSecurityKey=function(){var mt_rand=function(min,max){min=(arguments.length<1)?0:min;max=(arguments.length<2)?2147483647:max;return Math.floor(Math.random()*(max-min+1))+min};var chars="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()";for(var i=0,key="";i<64;i++){key+=chars.substr(mt_rand(0,chars.length-1),1)}$("input#ws-plugin--s2member-sec-encryption-key").val(key);return false};ws_plugin__s2member_enableSecurityKey=function(){if(confirm("Edit Key? Are you sure?\nThis could break your installation!\n\n*Note* If you've been testing s2Member, feel free to change this Key before you go live. Just don't go live, and then change it. You'll have unhappy Customers. Data corruption WILL occur! For your safety, s2Member keeps a history of the last 10 Keys that you've used. If you get yourself into a real situation, s2Member will let you revert back to a previous Key.")){$("input#ws-plugin--s2member-sec-encryption-key").removeAttr("disabled")}return false};ws_plugin__s2member_securityKeyHistory=function(){$("div#ws-plugin--s2member-sec-encryption-key-history").toggle();return false};$("select#ws-plugin--s2member-new-user-emails-enabled").change(function(){var $pluggable=$("input#ws-plugin--s2member-pluggables-wp-new-user-notification"),$this=$(this),$newUserEmails=$("div#ws-plugin--s2member-new-user-emails");if($pluggable.val()==="0"||$this.val()==="0"){($pluggable.val()==="0")?$this.attr("disabled","disabled"):$this.removeAttr("disabled");$(":input",$newUserEmails).attr("disabled","disabled"),$newUserEmails.css("opacity","0.5")}else{$this.removeAttr("disabled"),$(":input",$newUserEmails).removeAttr("disabled"),$newUserEmails.css("opacity","")}}).trigger("change");$("select#ws-plugin--s2member-login-reg-design-enabled").change(function(){var $this=$(this),$loginRegDesign=$("div#ws-plugin--s2member-login-reg-design");if($this.val()==="0"){$(":input",$loginRegDesign).attr("disabled","disabled"),$loginRegDesign.css("opacity","0.5"),$loginRegDesign.hide()}else{$(":input",$loginRegDesign).removeAttr("disabled"),$loginRegDesign.css("opacity",""),$loginRegDesign.show()}}).trigger("change");if($("input#ws-plugin--s2member-custom-reg-fields").length&&$("div#ws-plugin--s2member-custom-reg-field-configuration").length){(function(){var i,fieldDefaults,tools,table,$tools,$table;var $fields=$("input#ws-plugin--s2member-custom-reg-fields");var $configuration=$("div#ws-plugin--s2member-custom-reg-field-configuration");var fields=($fields.val())?$.JSON.parse($fields.val()):[];fields=(fields instanceof Array)?fields:[];fieldDefaults={section:"no",sectitle:"",id:"",label:"",type:"text",deflt:"",options:"",expected:"",required:"yes",levels:"all",editable:"yes",classes:"",styles:"",attrs:""};for(i=0;i<fields.length;i++){fields[i]=$.extend(true,{},fieldDefaults,fields[i])}tools='<div id="ws-plugin--s2member-custom-reg-field-configuration-tools"></div>',table='<table id="ws-plugin--s2member-custom-reg-field-configuration-table"></table>';$configuration.html(tools+table);$tools=$("div#ws-plugin--s2member-custom-reg-field-configuration-tools"),$table=$("table#ws-plugin--s2member-custom-reg-field-configuration-table");ws_plugin__s2member_customRegFieldSectionChange=function(select){var section=$(select).val();var sectitle_trs="tr.ws-plugin--s2member-custom-reg-field-configuration-tools-form-sectitle";(section==="yes")?$(sectitle_trs).css("display",""):$(sectitle_trs).css("display","none")};ws_plugin__s2member_customRegFieldTypeChange=function(select){var type=$(select).val();var deflt_trs="tr.ws-plugin--s2member-custom-reg-field-configuration-tools-form-deflt",options_trs="tr.ws-plugin--s2member-custom-reg-field-configuration-tools-form-options",expected_trs="tr.ws-plugin--s2member-custom-reg-field-configuration-tools-form-expected";(type.match(/^(text|textarea)$/))?$(deflt_trs).css("display",""):$(deflt_trs).css("display","none");(type.match(/^(select|selects|checkboxes|radios)$/))?$(options_trs).css("display",""):$(options_trs).css("display","none");(type.match(/^(text|textarea)$/))?$(expected_trs).css("display",""):$(expected_trs).css("display","none")};ws_plugin__s2member_customRegFieldDelete=function(index){var newFields=new Array();for(var i=0;i<fields.length;i++){if(i!==index){newFields.push(fields[i])}}fields=newFields,updateFields(),buildTable()};ws_plugin__s2member_customRegFieldMoveUp=function(index){if(typeof fields[index]==="object"&&typeof fields[index-1]==="object"){var prevFieldObj=fields[index-1],thisFieldObj=fields[index];fields[index-1]=thisFieldObj,fields[index]=prevFieldObj;updateFields(),buildTable()}};ws_plugin__s2member_customRegFieldMoveDown=function(index){if(typeof fields[index]==="object"&&typeof fields[index+1]==="object"){var nextFieldObj=fields[index+1],thisFieldObj=fields[index];fields[index+1]=thisFieldObj,fields[index]=nextFieldObj;updateFields(),buildTable()}};ws_plugin__s2member_customRegFieldCreate=function(){var $table=$("table#ws-plugin--s2member-custom-reg-field-configuration-tools-form"),field={};$(":input[property]",$table).each(function(){var $this=$(this),property=$this.attr("property"),val=$.trim($this.val());field[property]=val});if((field=validateField(field))){fields.push(field),updateFields(),buildTools(),buildTable(),scrollReset();setTimeout(function(){var row="tr.ws-plugin--s2member-custom-reg-field-configuration-table-row-"+(fields.length-1);alert('Field created successfully.\n* Remember to "Save All Changes".');$(row).effect("highlight",1500)},500)}};ws_plugin__s2member_customRegFieldUpdate=function(index){var $table=$("table#ws-plugin--s2member-custom-reg-field-configuration-tools-form"),field={};$(":input[property]",$table).each(function(){var $this=$(this),property=$this.attr("property"),val=$.trim($this.val());field[property]=val});if((field=validateField(field,index))){fields[index]=field,updateFields(),buildTools(),buildTable(),scrollReset();setTimeout(function(){var row="tr.ws-plugin--s2member-custom-reg-field-configuration-table-row-"+index;alert('Field updated successfully.\n* Remember to "Save All Changes".');$(row).effect("highlight",1500)},500)}};ws_plugin__s2member_customRegFieldAdd=function(){buildTools(true)};ws_plugin__s2member_customRegFieldEdit=function(index){buildTools(false,index),scrollReset()};ws_plugin__s2member_customRegFieldCancel=function(){buildTools(),scrollReset()};var validateField=function(field,index){var editing=(typeof index==="number"&&typeof fields[index]==="object")?true:false,errors=[],options,i;if(typeof field!=="object"||typeof(field=$.extend(true,{},fieldDefaults,field))!=="object"){alert("Invalid field object. Please try again.");return false}field.sectitle=(field.section==="yes")?field.sectitle:"";field.deflt=(field.type.match(/^(text|textarea)$/))?field.deflt:"";field.deflt=(field.type.match(/^(text)$/))?field.deflt.replace(/[\r\n\t ]+/g," "):field.deflt;field.options=(field.type.match(/^(select|selects|checkboxes|radios)$/))?field.options:"";field.expected=(field.type.match(/^(text|textarea)$/))?field.expected:"";if(!field.id){errors.push("Unique Field ID:\nThis is required. Please try again.")}else{if(fieldIdExists(field.id)&&(!editing||field.id!==fields[index].id)){errors.push("Unique Field ID:\nThat Field ID already exists. Please try again.")}}if(!field.label){errors.push("Field Label/Description:\nThis is required. Please try again.")}if(field.type.match(/^(select|selects|checkboxes|radios)$/)&&!field.options){errors.push("Option Configuration File:\nThis is required. Please try again.")}else{if(field.type.match(/^(select|selects|checkboxes|radios)$/)){for(i=0;i<(options=field.options.split(/[\r\n]+/)).length;i++){if(!(options[i]=$.trim(options[i])).match(/^([^\|]*)(\|)([^\|]*)(\|default)?$/)){errors.push("Option Configuration File:\nInvalid configuration at line #"+(i+1)+".");break}}field.options=$.trim(options.join("\n"))}}if(!(field.levels=field.levels.replace(/ /g,""))){errors.push("Applicable Levels:\nThis is required. Please try again.")}else{if(!field.levels.match(/^(all|[0-9,]+)$/)){errors.push("Applicable Levels:\nShould be comma-delimited Levels, or just type: all.\n(examples: 0,1,2,3,4 or type the word: all)")}}if(field.classes&&field.classes.match(/[^a-z 0-9 _ \-]/i)){errors.push("CSS Classes:\nContains invalid characters. Please try again.\n(only: alphanumerics, underscores, hyphens, spaces)")}if(field.styles&&field.styles.match(/["\=\>\<]/)){errors.push('CSS Styles:\nContains invalid characters. Please try again.\n(do NOT use these characters: = " < >)')}if(field.attrs&&field.attrs.match(/[\>\<]/)){errors.push("Other Attributes:\nContains invalid characters. Please try again.\n(do NOT use these characters: < >)")}if(errors.length>0){alert(errors.join("\n\n"));return false}else{return field}};var updateFields=function(){$fields.val(((fields.length>0)?$.JSON.stringify(fields):""))};var fieldId2Var=function(fieldId){return(typeof fieldId==="string")?$.trim(fieldId).toLowerCase().replace(/[^a-z0-9]/g,"_"):""};var fieldTypeDesc=function(type){var types={text:"Text (single line)",textarea:"Textarea (multi-line)",select:"Select Menu (drop-down)",selects:"Select Menu (multi-option)",checkbox:"Checkbox (single)",pre_checkbox:"Checkbox (pre-checked)",checkboxes:"Checkboxes (multi-option)",radios:"Radio Buttons (multi-option)"};if(typeof types[type]==="string"){return types[type]}return""};var fieldIdExists=function(fieldId){for(var i=0;i<fields.length;i++){if(fields[i].id===fieldId){return true}}};var scrollReset=function(){scrollTo(0,$("div.ws-plugin--s2member-custom-reg-fields-section").offset()["top"]-100)};var buildTools=function(adding,index){var i=0,html="",form="",w=0,h=0,editing=(typeof index==="number"&&typeof fields[index]==="object")?true:false,displayForm=(adding||editing)?true:false,field=(editing)?$.extend(true,{},fieldDefaults,fields[index]):fieldDefaults;html+='<a href="#" onclick="ws_plugin__s2member_customRegFieldAdd(); return false;">Add New Field</a>';tb_remove(),$("div#ws-plugin--s2member-custom-reg-field-configuration-thickbox-tools-form").remove();if(displayForm){form+='<div id="ws-plugin--s2member-custom-reg-field-configuration-thickbox-tools-form">';form+='<table id="ws-plugin--s2member-custom-reg-field-configuration-tools-form">';form+="<tbody>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-section">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-section">Starts A New Section?</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-section">';form+='<td colspan="2">';form+='<select property="section" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-section" onchange="ws_plugin__s2member_customRegFieldSectionChange(this);">';form+='<option value="no"'+((field.section==="no")?' selected="selected"':"")+'">No (this Field flows normally)</option>';form+='<option value="yes"'+((field.section==="yes")?' selected="selected"':"")+'">Yes (this Field begins a new section)</option>';form+="</select><br />";form+="<small>Optional. Allows Fields to be grouped into sections.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-sectitle ws-plugin--s2member-custom-reg-field-configuration-tools-form-section"'+((field.section==="yes")?"":' style="display:none;"')+'><td colspan="2"><hr /></td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-sectitle ws-plugin--s2member-custom-reg-field-configuration-tools-form-section"'+((field.section==="yes")?"":' style="display:none;"')+">";form+='<td colspan="2">';form+="Title for this new section? (optional)<br />";form+='<input type="text" property="sectitle" autocomplete="off" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-sectitle" value="'+esc_attr(field.sectitle)+'" /><br />';form+="<small>If empty, a simple divider will be used by default.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-type"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-type">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-type">Form Field Type: *</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-type">';form+='<td colspan="2">';form+='<select property="type" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-type" onchange="ws_plugin__s2member_customRegFieldTypeChange(this);">';form+='<option value="text"'+((field.type==="text")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("text"))+"</option>";form+='<option value="textarea"'+((field.type==="textarea")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("textarea"))+"</option>";form+='<option value="select"'+((field.type==="select")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("select"))+"</option>";form+='<option value="selects"'+((field.type==="selects")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("selects"))+"</option>";form+='<option value="checkbox"'+((field.type==="checkbox")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("checkbox"))+"</option>";form+='<option value="pre_checkbox"'+((field.type==="pre_checkbox")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("pre_checkbox"))+"</option>";form+='<option value="checkboxes"'+((field.type==="checkboxes")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("checkboxes"))+"</option>";form+='<option value="radios"'+((field.type==="radios")?' selected="selected"':"")+'">'+esc_html(fieldTypeDesc("radios"))+"</option>";form+="</select><br />";form+="<small>The options below may change, based on the Field Type you choose here.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-label"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-label">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-label">Field Label/Desc: *</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-label">';form+='<td colspan="2">';form+='<input type="text" property="label" autocomplete="off" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-label" value="'+esc_attr(field.label)+'" /><br />';form+="<small>Examples: <code>Choose Country</code>, <code>Street Address</code></small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-id"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-id">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-id">Unique Field ID: *</label></label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-id">';form+='<td colspan="2">';form+='<input type="text" property="id" maxlength="25" autocomplete="off" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-id" value="'+esc_attr(field.id)+'" /><br />';form+="<small>Examples: <code>country_code</code>, <code>street_address</code></small><br />";form+='<small>e.g. <code>[s2Get user_field="country_code" /]</code></small>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-required"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-required">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-required">Field Required: *</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-required">';form+='<td colspan="2">';form+='<select property="required" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-required">';form+='<option value="yes"'+((field.required==="yes")?' selected="selected"':"")+'">Yes (required)</option>';form+='<option value="no"'+((field.required==="no")?' selected="selected"':"")+'">No (optional)</option>';form+="</select><br />";form+='<small>If <code>yes</code>, only Users/Members will be "required" to enter this field.</small><br />';form+="<small>* Administrators are exempt from this requirement.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-deflt"'+((field.type.match(/^(text|textarea)$/))?"":' style="display:none;"')+'><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-deflt"'+((field.type.match(/^(text|textarea)$/))?"":' style="display:none;"')+">";form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-deflt">Default Text Value: (optional)</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-deflt"'+((field.type.match(/^(text|textarea)$/))?"":' style="display:none;"')+">";form+='<td colspan="2">';form+='<textarea property="deflt" wrap="off" spellcheck="false" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-deflt" rows="1">'+esc_html(field.deflt)+"</textarea><br />";form+="<small>Default value before user input is received.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-options"'+((field.type.match(/^(select|selects|checkboxes|radios)$/))?"":' style="display:none;"')+'><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-options"'+((field.type.match(/^(select|selects|checkboxes|radios)$/))?"":' style="display:none;"')+">";form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-options">Option Configuration File: * (one option per line)</label><br />';form+="<small>Use a pipe <code>|</code> delimited format: <code>option value|option label</code></small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-options"'+((field.type.match(/^(select|selects|checkboxes|radios)$/))?"":' style="display:none;"')+">";form+='<td colspan="2">';form+='<textarea property="options" wrap="off" spellcheck="false" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-options" rows="3">'+esc_html(field.options)+"</textarea><br />";form+="Here is a quick example:<br />";form+="<small>You can also specify a <em>default</em> option:</small><br />";form+="<code>US|United States|default</code><br />";form+="<code>CA|Canada</code><br />";form+="<code>VI|Virgin Islands (U.S.)</code>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-expected"'+((field.type.match(/^(text|textarea)$/))?"":' style="display:none;"')+'><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-expected"'+((field.type.match(/^(text|textarea)$/))?"":' style="display:none;"')+">";form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-expected">Expected Format: *</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-expected"'+((field.type.match(/^(text|textarea)$/))?"":' style="display:none;"')+">";form+='<td colspan="2">';form+='<select property="expected" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-expected">';form+='<option value=""'+((field.expected==="")?' selected="selected"':"")+'">Anything Goes</option>';form+='<option disabled="disabled"></option>';form+='<optgroup label="Specific Input Types">';form+='<option value="numeric-wp-commas"'+((field.expected==="numeric-wp-commas")?' selected="selected"':"")+'">Numeric (with or without decimals, commas allowed)</option>';form+='<option value="numeric"'+((field.expected==="numeric")?' selected="selected"':"")+'">Numeric (with or without decimals, no commas)</option>';form+='<option value="integer"'+((field.expected==="integer")?' selected="selected"':"")+'">Integer (whole number, without any decimals)</option>';form+='<option value="integer-gt-0"'+((field.expected==="integer-gt-0")?' selected="selected"':"")+'">Integer > 0 (whole number, no decimals, greater than 0)</option>';form+='<option value="float"'+((field.expected==="float")?' selected="selected"':"")+'">Float (floating point number, decimals required)</option>';form+='<option value="float-gt-0"'+((field.expected==="float-gt-0")?' selected="selected"':"")+'">Float > 0 (floating point number, decimals required, greater than 0)</option>';form+='<option value="date"'+((field.expected==="date")?' selected="selected"':"")+'">Date (required date format: dd/mm/yyyy)</option>';form+='<option value="email"'+((field.expected==="email")?' selected="selected"':"")+'">Email (require valid email)</option>';form+='<option value="url"'+((field.expected==="url")?' selected="selected"':"")+'">Full URL (starting with http or https)</option>';form+='<option value="domain"'+((field.expected==="domain")?' selected="selected"':"")+'">Domain Name (domain name only, without http)</option>';form+='<option value="phone"'+((field.expected==="phone")?' selected="selected"':"")+'">Phone # (10 digits w/possible hyphens,spaces,brackets)</option>';form+='<option value="uszip"'+((field.expected==="uszip")?' selected="selected"':"")+'">US Zipcode (5-9 digits w/possible hyphen)</option>';form+='<option value="cazip"'+((field.expected==="cazip")?' selected="selected"':"")+'">Canadian Zipcode (6 alpha-numerics w/possible space)</option>';form+='<option value="uczip"'+((field.expected==="uczip")?' selected="selected"':"")+'">US/Canadian Zipcode (either a US or Canadian zipcode)</option>';form+="</optgroup>";form+='<option disabled="disabled"></option>';form+='<optgroup label="Any Character Combination">';for(i=1;i<=25;i++){form+='<option value="any-'+i+'"'+((field.expected==="any-"+i)?' selected="selected"':"")+'">Any Character Combination ( '+i+" character minimum )</option>";form+='<option value="any-'+i+'-e"'+((field.expected==="any-"+i+"-e")?' selected="selected"':"")+'">Any Character Combination ( exactly '+i+" character"+((i>1)?"s":"")+" )</option>"}form+="</optgroup>";form+='<option disabled="disabled"></option>';form+='<optgroup label="Alphanumerics, Spaces &amp; Punctuation Only">';for(i=1;i<=25;i++){form+='<option value="alphanumerics-spaces-punctuation-'+i+'"'+((field.expected==="alphanumerics-spaces-punctuation-"+i)?' selected="selected"':"")+'">Alphanumerics, Spaces &amp; Punctuation ( '+i+" character minimum )</option>";form+='<option value="alphanumerics-spaces-punctuation-'+i+'-e"'+((field.expected==="alphanumerics-spaces-punctuation-"+i+"-e")?' selected="selected"':"")+'">Alphanumerics, Spaces &amp; Punctuation ( exactly '+i+" character"+((i>1)?"s":"")+" )</option>"}form+="</optgroup>";form+='<option disabled="disabled"></option>';form+='<optgroup label="Alphanumerics &amp; Spaces Only">';for(i=1;i<=25;i++){form+='<option value="alphanumerics-spaces-'+i+'"'+((field.expected==="alphanumerics-spaces-"+i)?' selected="selected"':"")+'">Alphanumerics &amp; Spaces ( '+i+" character minimum )</option>";form+='<option value="alphanumerics-spaces-'+i+'-e"'+((field.expected==="alphanumerics-spaces-"+i+"-e")?' selected="selected"':"")+'">Alphanumerics &amp; Spaces ( exactly '+i+" character"+((i>1)?"s":"")+" )</option>"}form+="</optgroup>";form+='<option disabled="disabled"></option>';form+='<optgroup label="Alphanumerics &amp; Punctuation Only">';for(i=1;i<=25;i++){form+='<option value="alphanumerics-punctuation-'+i+'"'+((field.expected==="alphanumerics-punctuation-"+i)?' selected="selected"':"")+'">Alphanumerics &amp; Punctuation ( '+i+" character minimum )</option>";form+='<option value="alphanumerics-punctuation-'+i+'-e"'+((field.expected==="alphanumerics-punctuation-"+i+"-e")?' selected="selected"':"")+'">Alphanumerics &amp; Punctuation ( exactly '+i+" character"+((i>1)?"s":"")+" )</option>"}form+="</optgroup>";form+='<option disabled="disabled"></option>';form+='<optgroup label="Alphanumerics Only">';for(i=1;i<=25;i++){form+='<option value="alphanumerics-'+i+'"'+((field.expected==="alphanumerics-"+i)?' selected="selected"':"")+'">Alphanumerics ( '+i+" character minimum )</option>";form+='<option value="alphanumerics-'+i+'-e"'+((field.expected==="alphanumerics-"+i+"-e")?' selected="selected"':"")+'">Alphanumerics ( exactly '+i+" character"+((i>1)?"s":"")+" )</option>"}form+="</optgroup>";form+='<option disabled="disabled"></option>';form+='<optgroup label="Alphabetics Only">';for(i=1;i<=25;i++){form+='<option value="alphabetics-'+i+'"'+((field.expected==="alphabetics-"+i)?' selected="selected"':"")+'">Alphabetics ( '+i+" character minimum )</option>";form+='<option value="alphabetics-'+i+'-e"'+((field.expected==="alphabetics-"+i+"-e")?' selected="selected"':"")+'">Alphabetics ( exactly '+i+" character"+((i>1)?"s":"")+" )</option>"}form+="</optgroup>";form+='<option disabled="disabled"></option>';form+='<optgroup label="Numeric Digits Only">';for(i=1;i<=25;i++){form+='<option value="numerics-'+i+'"'+((field.expected==="numerics-"+i)?' selected="selected"':"")+'">Numeric Digits ( '+i+" digit minimum )</option>";form+='<option value="numerics-'+i+'-e"'+((field.expected==="numerics-"+i+"-e")?' selected="selected"':"")+'">Numeric Digits ( exactly '+i+" digit"+((i>1)?"s":"")+" )</option>"}form+="</optgroup>";form+="</select><br />";form+="<small>Only Users/Members will be required to meet this criteria.</small><br />";form+="<small>* Administrators are exempt from this.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-levels"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-levels">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-levels">Applicable Membership Levels: *</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-levels">';form+='<td colspan="2">';form+='<input type="text" property="levels" autocomplete="off" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-levels" value="'+esc_attr(field.levels)+'" /><br />';form+="<small>Please use comma-delimited Level #'s: <code>0,1,2,3,4</code> or type: <code>all</code>.</small><br />";form+="<small>This allows you to enable this field - only at specific Membership Levels.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-editable"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-editable">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-editable">Allow Profile Edits: *</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-editable">';form+='<td colspan="2">';form+='<select property="editable" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-editable">';form+='<option value="yes"'+((field.editable==="yes")?' selected="selected"':"")+'">Yes (editable)</option>';form+='<option value="no"'+((field.editable==="no")?' selected="selected"':"")+'">No (uneditable after registration)</option>';form+='<option value="no-invisible"'+((field.editable==="no-invisible")?' selected="selected"':"")+'">No (uneditable &amp; totally invisible after registration)</option>';form+='<option value="no-always-invisible"'+((field.editable==="no-always-invisible")?' selected="selected"':"")+'">No (uneditable &amp; totally invisible, both during &amp; after registration)</option>';form+='<option value="yes-invisible"'+((field.editable==="yes-invisible")?' selected="selected"':"")+'">Yes (editable after registration / invisible during registration)</option>';form+="</select><br />";form+="<small>If <code>No</code>, this field will be un-editable after registration.</small><br />";form+="<small>* Administrators are exempt from this.</small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-classes"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-classes">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-classes">CSS Classes: (optional)</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-classes">';form+='<td colspan="2">';form+='<input type="text" property="classes" autocomplete="off" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-classes" value="'+esc_attr(field.classes)+'" /><br />';form+="<small>Example: <code>my-style-1 my-style-2</code></small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-styles"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-styles">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-styles">CSS Styles: (optional)</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-styles">';form+='<td colspan="2">';form+='<input type="text" property="styles" autocomplete="off" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-styles" value="'+esc_attr(field.styles)+'" /><br />';form+="<small>Example: <code>color:#000000; background:#FFFFFF;</code></small>";form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-attrs"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-attrs">';form+='<td colspan="2">';form+='<label for="ws-plugin--s2member-custom-reg-field-configuration-tools-form-attrs">Other Attributes: (optional)</label>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-attrs">';form+='<td colspan="2">';form+='<input type="text" property="attrs" autocomplete="off" id="ws-plugin--s2member-custom-reg-field-configuration-tools-form-attrs" value="'+esc_attr(field.attrs)+'" /><br />';form+='<small>Example: <code>onkeyup="" onblur=""</code></small>';form+="</td>";form+="</tr>";form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-spacer ws-plugin--s2member-custom-reg-field-configuration-tools-form-buttons"><td colspan="2">&nbsp;</td></tr>';form+='<tr class="ws-plugin--s2member-custom-reg-field-configuration-tools-form-buttons">';form+='<td align="left">';form+='<input type="button" value="Cancel" onclick="ws_plugin__s2member_customRegFieldCancel();" />';form+="</td>";form+='<td align="right">';form+='<input type="button" value="'+((editing)?"Update This Field":"Create Registration Field")+'" onclick="'+((editing)?"ws_plugin__s2member_customRegFieldUpdate("+index+");":"ws_plugin__s2member_customRegFieldCreate();")+'" />';form+="</td>";form+="</tr>";form+="</tbody>";form+="</table>";form+="<div>";$("body").append(form);tb_show(((editing)?"Editing Registration/Profile Field":"New Custom Registration/Profile Field"),"#TB_inline?inlineId=ws-plugin--s2member-custom-reg-field-configuration-thickbox-tools-form");$("table#ws-plugin--s2member-custom-reg-field-configuration-tools-form").show()}$tools.html(html)};var buildTable=function(){var l=fields.length,i=0,html="",eo="o";html+="<tbody>";html+="<tr>";html+="<th>Order</th>";html+="<th>Field Type</th>";html+="<th>Unique ID</th>";html+="<th>Required</th>";html+="<th>Levels</th>";html+="<th>- Tools -</th>";html+="</tr>";if(fields.length>0){for(i=0;i<fields.length;i++){html+='<tr class="'+esc_attr((eo=(eo==="o")?"e":"o"))+((fields[i].section==="yes")?" s":"")+" ws-plugin--s2member-custom-reg-field-configuration-table-row-"+i+'">';html+='<td nowrap="nowrap"><a class="ws-plugin--s2member-custom-reg-field-configuration-move-up" href="#" onclick="ws_plugin__s2member_customRegFieldMoveUp('+i+'); return false;"></a><a class="ws-plugin--s2member-custom-reg-field-configuration-move-down" href="#" onclick="ws_plugin__s2member_customRegFieldMoveDown('+i+'); return false;"></a></td>';html+='<td nowrap="nowrap">'+esc_html(fieldTypeDesc(fields[i].type))+"</td>";html+='<td nowrap="nowrap">'+esc_html(fields[i].id)+"</td>";html+='<td nowrap="nowrap">'+esc_html(fields[i].required)+"</td>";html+='<td nowrap="nowrap">'+esc_html(fields[i].levels)+"</td>";html+='<td nowrap="nowrap"><a class="ws-plugin--s2member-custom-reg-field-configuration-edit" href="#" onclick="ws_plugin__s2member_customRegFieldEdit('+i+'); return false;"></a><a class="ws-plugin--s2member-custom-reg-field-configuration-delete" href="#" onclick="ws_plugin__s2member_customRegFieldDelete('+i+'); return false;"></a></td>';html+="</tr>"}}else{html+="<tr>";html+='<td colspan="6">No Custom Fields are configured.</td>';html+="</tr>"}html+="</tbody>";$table.html(html)};buildTools(),buildTable()})()}}if(location.href.match(/page\=ws-plugin--s2member-res-ops/)){$("input#ws-plugin--s2member-brute-force-restrictions-reset-button").click(function(){var $this=$(this);$this.val("one moment please ...");$.post(ajaxurl,{action:"ws_plugin__s2member_delete_reset_all_ip_restrictions_via_ajax",ws_plugin__s2member_delete_reset_all_ip_restrictions_via_ajax:'<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (wp_create_nonce ("ws-plugin--s2member-delete-reset-all-ip-restrictions-via-ajax")); ?>'},function(response){alert("s2Member's Brute Force Restriction Logs have all been reset."),$this.val("Reset Brute Force Logs")});return false});$("input#ws-plugin--s2member-ip-restrictions-reset-button").click(function(){var $this=$(this);$this.val("one moment please ...");$.post(ajaxurl,{action:"ws_plugin__s2member_delete_reset_all_ip_restrictions_via_ajax",ws_plugin__s2member_delete_reset_all_ip_restrictions_via_ajax:'<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (wp_create_nonce ("ws-plugin--s2member-delete-reset-all-ip-restrictions-via-ajax")); ?>'},function(response){alert("s2Member's IP Restriction Logs have all been reset."),$this.val("Reset IP Restriction Logs")});return false});$('div.ws-plugin--s2member-query-level-access-section input[type="checkbox"][name="ws_plugin__s2member_filter_wp_query[]"]').change(function(){var thisChange=$(this).val();$('div.ws-plugin--s2member-query-level-access-section input[type="checkbox"][name="ws_plugin__s2member_filter_wp_query[]"]').each(function(){var $this=$(this),val=$this.val(),checkboxes='input[type="checkbox"]';if(val==="all"&&this.checked){$this.nextAll(checkboxes).attr({checked:"checked",disabled:"disabled"})}else{if(val==="all"&&!this.checked){$this.nextAll(checkboxes).removeAttr("disabled");(thisChange==="all")?$this.nextAll(checkboxes).removeAttr("checked"):null}}})}).last().trigger("change")}if(location.href.match(/page\=ws-plugin--s2member-down-ops/)){var updateCloudFrontPrivateKey=function(){var $hiddenPrivateKey=$("input#ws-plugin--s2member-amazon-cf-files-private-key");var $visiblePrivateKeyEntry=$("textarea#ws-plugin--s2member-amazon-cf-files-private-key-entry");var hiddenPrivateKeyValue=$.trim($hiddenPrivateKey.val()),visiblePrivateKeyEntryValue=$.trim($visiblePrivateKeyEntry.val());if((hiddenPrivateKeyValue&&!visiblePrivateKeyEntryValue)||visiblePrivateKeyEntryValue.match(/[^\r\n\u25CF]/)){$hiddenPrivateKey.val(visiblePrivateKeyEntryValue),$visiblePrivateKeyEntry.val(visiblePrivateKeyEntryValue.replace(/[^\r\n]/g,String.fromCharCode(9679)))}};$("form#ws-plugin--s2member-options-form").submit(updateCloudFrontPrivateKey);$("textarea#ws-plugin--s2member-amazon-cf-files-private-key-entry").change(updateCloudFrontPrivateKey).trigger("change");var updateCloudFrontDistroCfgs=function(){var $hiddenPrivateKey=$("input#ws-plugin--s2member-amazon-cf-files-private-key");var $visiblePrivateKeyId=$("input#ws-plugin--s2member-amazon-cf-files-private-key-id");var $autoConfigDistros=$("input#ws-plugin--s2member-amazon-cf-files-auto-configure-distros");var $autoConfigDistrosStatus=$("input#ws-plugin--s2member-amazon-cf-files-distros-auto-config-status");var autoConfigDistrosStatusValue=$.trim($autoConfigDistrosStatus.val());var hiddenPrivateKeyValue=$.trim($hiddenPrivateKey.val()),visiblePrivateKeyIdValue=$.trim($visiblePrivateKeyId.val());var hiddenPrivateKeyPrevConfigValue=$.trim($hiddenPrivateKey.attr("data-s-prev-config-value")),visiblePrivateKeyIdPrevConfigValue=$.trim($visiblePrivateKeyId.attr("data-s-prev-config-value"));if(autoConfigDistrosStatusValue==="configured"&&((visiblePrivateKeyIdPrevConfigValue&&visiblePrivateKeyIdValue!==visiblePrivateKeyIdPrevConfigValue)||(hiddenPrivateKeyPrevConfigValue&&hiddenPrivateKeyValue!==hiddenPrivateKeyPrevConfigValue))){alert("s2Member will need to delete and re-configure your Amazon CloudFront distributions if you change this. When you're done editing, click (Save All Changes) below.");$autoConfigDistros.attr("checked","checked")}else{if(autoConfigDistrosStatusValue!=="configured"&&visiblePrivateKeyIdValue&&hiddenPrivateKeyValue){alert("s2Member will need to auto-configure your Amazon CloudFront distributions for you. When you're done editing, click (Save All Changes) below.");$autoConfigDistros.attr("checked","checked")}}};$("input#ws-plugin--s2member-amazon-cf-files-private-key-id").change(updateCloudFrontDistroCfgs);$("textarea#ws-plugin--s2member-amazon-cf-files-private-key-entry").change(updateCloudFrontDistroCfgs);$("input#ws-plugin--s2member-amazon-cf-files-auto-configure-distros-w-cnames").change(function(){var $this=$(this),thisChecked=(this.checked)?true:false;var $autoConfigDistros=$("input#ws-plugin--s2member-amazon-cf-files-auto-configure-distros");var $autoConfigDistroCnames=$("div#ws-plugin--s2member-amazon-cf-files-auto-configure-distro-cnames");(thisChecked)?$autoConfigDistroCnames.show():$autoConfigDistroCnames.hide();(thisChecked)?$autoConfigDistros.attr("checked","checked"):null}).trigger("change")}if(location.href.match(/page\=ws-plugin--s2member-paypal-ops/)){$("select#ws-plugin--s2member-auto-eot-system-enabled").change(function(){var $this=$(this),val=$this.val();var $viaCron=$("p#ws-plugin--s2member-auto-eot-system-enabled-via-cron");if(val==2){$viaCron.show()}else{$viaCron.hide()}})}if(location.href.match(/page\=ws-plugin--s2member-paypal-buttons/)){$("div.ws-menu-page select[id]").filter(function(){return this.id.match(/^ws-plugin--s2member-(level[1-9][0-9]*|modification)-term$/)}).change(function(){var button=this.id.replace(/^ws-plugin--s2member-(.+?)-term$/g,"$1");var trialDisabled=($(this).val().split("-")[2].replace(/[^0-1BN]/g,"")==="BN")?1:0;$("p#ws-plugin--s2member-"+button+"-trial-line").css("display",(trialDisabled?"none":""));$("span#ws-plugin--s2member-"+button+"-trial-then").css("display",(trialDisabled?"none":""));$("span#ws-plugin--s2member-"+button+"-20p-rule").css("display",(trialDisabled?"none":""));(trialDisabled)?$("input#ws-plugin--s2member-"+button+"-trial-period").val(0):null;(trialDisabled)?$("input#ws-plugin--s2member-"+button+"-trial-amount").val("0.00"):null});$("div.ws-menu-page input[id]").filter(function(){return this.id.match(/^ws-plugin--s2member-(level[1-9][0-9]*|modification|ccap)-ccaps$/)}).keyup(function(){var value=this.value.replace(/^(-all|-al|-a|-)[;,]*/gi,""),_all=(this.value.match(/^(-all|-al|-a|-)[;,]*/i))?"-all,":"";if(value.match(/[^a-z_0-9,]/)){this.value=_all+$.trim($.trim(value).replace(/[ \-]/g,"_").replace(/[^a-z_0-9,]/gi,"").toLowerCase())}});ws_plugin__s2member_paypalButtonGenerate=function(button){var shortCodeTemplate='[s2Member-PayPal-Button %%attrs%% image="default" output="button" /]',shortCodeTemplateAttrs="",labels={};eval("<?php echo c_ws_plugin__s2member_utils_strings::esc_dq($labels); ?>");var shortCode=$("input#ws-plugin--s2member-"+button+"-shortcode");var code=$("textarea#ws-plugin--s2member-"+button+"-button");var modLevel=$("select#ws-plugin--s2member-modification-level");var level=(button==="modification")?modLevel.val().split(":",2)[1]:button.replace(/^level/,"");var label=labels["level"+level].replace(/"/g,"");var desc=$.trim($("input#ws-plugin--s2member-"+button+"-desc").val().replace(/"/g,""));var trialAmount=$("input#ws-plugin--s2member-"+button+"-trial-amount").val().replace(/[^0-9\.]/g,"");var trialPeriod=$("input#ws-plugin--s2member-"+button+"-trial-period").val().replace(/[^0-9]/g,"");var trialTerm=$("select#ws-plugin--s2member-"+button+"-trial-term").val().replace(/[^A-Z]/g,"");var regAmount=$("input#ws-plugin--s2member-"+button+"-amount").val().replace(/[^0-9\.]/g,"");var regPeriod=$("select#ws-plugin--s2member-"+button+"-term").val().split("-")[0].replace(/[^0-9]/g,"");var regTerm=$("select#ws-plugin--s2member-"+button+"-term").val().split("-")[1].replace(/[^A-Z]/g,"");var regRecur=$("select#ws-plugin--s2member-"+button+"-term").val().split("-")[2].replace(/[^0-1BN]/g,"");var regRecurTimes="",regRecurRetry="1";var localeCode="",digital="0",noShipping="1";var pageStyle=$.trim($("input#ws-plugin--s2member-"+button+"-page-style").val().replace(/"/g,""));var currencyCode=$("select#ws-plugin--s2member-"+button+"-currency").val().replace(/[^A-Z]/g,"");var cCaps=$.trim($.trim($("input#ws-plugin--s2member-"+button+"-ccaps").val()).replace(/^(-all|-al|-a|-)[;,]*/gi,"").replace(/[ \-]/g,"_").replace(/[^a-z_0-9,]/gi,"").toLowerCase());cCaps=($.trim($("input#ws-plugin--s2member-"+button+"-ccaps").val()).match(/^(-all|-al|-a|-)[;,]*/i))?((cCaps)?"-all,":"-all")+cCaps.toLowerCase():cCaps.toLowerCase();trialPeriod=(regRecur==="BN")?"0":trialPeriod;trialAmount=(!trialAmount||isNaN(trialAmount)||trialAmount<0.01||trialPeriod<=0)?"0":trialAmount;var levelCcapsPer=(regRecur==="BN"&&regTerm!=="L")?level+":"+cCaps+":"+regPeriod+" "+regTerm:level+":"+cCaps;levelCcapsPer=levelCcapsPer.replace(/\:+$/g,"");if(trialAmount!=="0"&&(isNaN(trialAmount)||trialAmount<0)){alert("— Oops, a slight problem: —\n\nWhen provided, Trial Amount must be >= 0.00");return false}else{if(trialAmount!=="0"&&trialAmount>10000&&currencyCode.toUpperCase()==="USD"){alert("— Oops, a slight problem: —\n\nMaximum Trial Amount is: 10000.00");return false}else{if(trialTerm==="D"&&trialPeriod>90){alert("— Oops, a slight problem: —\n\nMaximum Trial Days is: 90.\nIf you want to offer more than 90 days, please choose Weeks or Months from the drop-down.");return false}else{if(trialTerm==="W"&&trialPeriod>52){alert("— Oops, a slight problem: —\n\nMaximum Trial Weeks is: 52.\nIf you want to offer more than 52 weeks, please choose Months from the drop-down.");return false}else{if(trialTerm==="M"&&trialPeriod>24){alert("— Oops, a slight problem: —\n\nMaximum Trial Months is: 24.\nIf you want to offer more than 24 months, please choose Years from the drop-down.");return false}else{if(trialTerm==="Y"&&trialPeriod>5){alert("— Oops, a slight problem: —\n\nMax Trial Period Years is: 5.");return false}else{if(!regAmount||isNaN(regAmount)||regAmount<0.01){alert("— Oops, a slight problem: —\n\nAmount must be >= 0.01");return false}else{if(regAmount>10000&&currencyCode.toUpperCase()==="USD"){alert("— Oops, a slight problem: —\n\nMaximum Amount is: 10000.00");return false}else{if(!desc){alert("— Oops, a slight problem: —\n\nPlease type a Description for this Button.");return false}}}}}}}}}code.html(code.val().replace(/ \<\!--(\<input type\="hidden" name\="(amount|src|srt|sra|a1|p1|t1|a3|p3|t3)" value\="(.*?)" \/\>)--\>/g," $1"));(parseInt(trialPeriod)<=0)?code.html(code.val().replace(/ (\<input type\="hidden" name\="(a1|p1|t1)" value\="(.*?)" \/\>)/g," <!--$1-->")):null;(regRecur==="BN")?code.html(code.val().replace(/ (\<input type\="hidden" name\="cmd" value\=")(.*?)(" \/\>)/g," $1_xclick$3")):null;(regRecur==="BN")?code.html(code.val().replace(/ (\<input type\="hidden" name\="(src|srt|sra|a1|p1|t1|a3|p3|t3)" value\="(.*?)" \/\>)/g," <!--$1-->")):null;(regRecur!=="BN")?code.html(code.val().replace(/ (\<input type\="hidden" name\="cmd" value\=")(.*?)(" \/\>)/g," $1_xclick-subscriptions$3")):null;(regRecur!=="BN")?code.html(code.val().replace(/ (\<input type\="hidden" name\="amount" value\="(.*?)" \/\>)/g," <!--$1-->")):null;shortCodeTemplateAttrs+=(button==="modification")?'modify="1" ':"";shortCodeTemplateAttrs+='level="'+esc_attr(level)+'" ccaps="'+esc_attr(cCaps)+'" desc="'+esc_attr(desc)+'" ps="'+esc_attr(pageStyle)+'" lc="'+esc_attr(localeCode)+'" cc="'+esc_attr(currencyCode)+'" dg="'+esc_attr(digital)+'" ns="'+esc_attr(noShipping)+'" custom="<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"])); ?>"';shortCodeTemplateAttrs+=' ta="'+esc_attr(trialAmount)+'" tp="'+esc_attr(trialPeriod)+'" tt="'+esc_attr(trialTerm)+'" ra="'+esc_attr(regAmount)+'" rp="'+esc_attr(regPeriod)+'" rt="'+esc_attr(regTerm)+'" rr="'+esc_attr(regRecur)+'" rrt="'+esc_attr(regRecurTimes)+'" rra="'+esc_attr(regRecurRetry)+'"';shortCode.val(shortCodeTemplate.replace(/%%attrs%%/,shortCodeTemplateAttrs));code.html(code.val().replace(/ name\="lc" value\="(.*?)"/,' name="lc" value="'+esc_attr(localeCode)+'"'));code.html(code.val().replace(/ name\="no_shipping" value\="(.*?)"/,' name="no_shipping" value="'+esc_attr(noShipping)+'"'));code.html(code.val().replace(/ name\="item_name" value\="(.*?)"/,' name="item_name" value="'+esc_attr(desc)+'"'));code.html(code.val().replace(/ name\="item_number" value\="(.*?)"/,' name="item_number" value="'+esc_attr(levelCcapsPer)+'"'));code.html(code.val().replace(/ name\="page_style" value\="(.*?)"/,' name="page_style" value="'+esc_attr(pageStyle)+'"'));code.html(code.val().replace(/ name\="currency_code" value\="(.*?)"/,' name="currency_code" value="'+esc_attr(currencyCode)+'"'));code.html(code.val().replace(/ name\="custom" value\="(.*?)"/,' name="custom" value="<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"])); ?>"'));code.html(code.val().replace(/ name\="modify" value\="(.*?)"/,' name="modify" value="'+((button==="modification")?"1":"0")+'"'));code.html(code.val().replace(/ name\="amount" value\="(.*?)"/,' name="amount" value="'+esc_attr(regAmount)+'"'));code.html(code.val().replace(/ name\="src" value\="(.*?)"/,' name="src" value="'+esc_attr(regRecur)+'"'));code.html(code.val().replace(/ name\="srt" value\="(.*?)"/,' name="srt" value="'+esc_attr(regRecurTimes)+'"'));code.html(code.val().replace(/ name\="sra" value\="(.*?)"/,' name="sra" value="'+esc_attr(regRecurRetry)+'"'));code.html(code.val().replace(/ name\="a1" value\="(.*?)"/,' name="a1" value="'+esc_attr(trialAmount)+'"'));code.html(code.val().replace(/ name\="p1" value\="(.*?)"/,' name="p1" value="'+esc_attr(trialPeriod)+'"'));code.html(code.val().replace(/ name\="t1" value\="(.*?)"/,' name="t1" value="'+esc_attr(trialTerm)+'"'));code.html(code.val().replace(/ name\="a3" value\="(.*?)"/,' name="a3" value="'+esc_attr(regAmount)+'"'));code.html(code.val().replace(/ name\="p3" value\="(.*?)"/,' name="p3" value="'+esc_attr(regPeriod)+'"'));code.html(code.val().replace(/ name\="t3" value\="(.*?)"/,' name="t3" value="'+esc_attr(regTerm)+'"'));$("div#ws-plugin--s2member-"+button+"-button-prev").html(code.val().replace(/\<form/,'<form target="_blank"').replace(/\<\?php echo S2MEMBER_VALUE_FOR_PP_INV\(\); \?\>/g,Math.round(new Date().getTime())+'~<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["REMOTE_ADDR"])); ?>').replace(/\<\?php echo S2MEMBER_CURRENT_USER_VALUE_FOR_PP_(ON0|OS0|ON1|OS1); \?\>/g,""));(button==="modification")?alert("Your Modification Button has been generated.\nPlease copy/paste the Shortcode into your Login Welcome Page, or wherever you feel it would be most appropriate.\n\n* Remember, Modification Buttons should be displayed to existing Users/Members, and they should be logged-in, BEFORE clicking this Button."):alert("Your Button has been generated.\nPlease copy/paste the Shortcode Format into your Membership Options Page.");shortCode.each(function(){this.focus(),this.select()});return false};ws_plugin__s2member_paypalCcapButtonGenerate=function(){var shortCodeTemplate='[s2Member-PayPal-Button %%attrs%% image="default" output="button" /]',shortCodeTemplateAttrs="";var shortCode=$("input#ws-plugin--s2member-ccap-shortcode");var code=$("textarea#ws-plugin--s2member-ccap-button");var desc=$.trim($("input#ws-plugin--s2member-ccap-desc").val().replace(/"/g,""));var regAmount=$("input#ws-plugin--s2member-ccap-amount").val().replace(/[^0-9\.]/g,"");var regPeriod=$("select#ws-plugin--s2member-ccap-term").val().split("-")[0].replace(/[^0-9]/g,"");var regTerm=$("select#ws-plugin--s2member-ccap-term").val().split("-")[1].replace(/[^A-Z]/g,"");var regRecur=$("select#ws-plugin--s2member-ccap-term").val().split("-")[2].replace(/[^0-1BN]/g,"");var localeCode="",digital="0",noShipping="1";var pageStyle=$.trim($("input#ws-plugin--s2member-ccap-page-style").val().replace(/"/g,""));var currencyCode=$("select#ws-plugin--s2member-ccap-currency").val().replace(/[^A-Z]/g,"");var cCaps=$.trim($.trim($("input#ws-plugin--s2member-ccap-ccaps").val()).replace(/^(-all|-al|-a|-)[;,]*/gi,"").replace(/[ \-]/g,"_").replace(/[^a-z_0-9,]/gi,"").toLowerCase());cCaps=($.trim($("input#ws-plugin--s2member-ccap-ccaps").val()).match(/^(-all|-al|-a|-)[;,]*/i))?((cCaps)?"-all,":"-all")+cCaps.toLowerCase():cCaps.toLowerCase();var levelCcapsPer=(regRecur==="BN"&&regTerm!=="L")?"*:"+cCaps+":"+regPeriod+" "+regTerm:"*:"+cCaps;levelCcapsPer=levelCcapsPer.replace(/\:+$/g,"");if(!cCaps||cCaps==="-all"){alert("— Oops, a slight problem: —\n\nPlease provide at least one Custom Capability.");return false}else{if(!regAmount||isNaN(regAmount)||regAmount<0.01){alert("— Oops, a slight problem: —\n\nAmount must be >= 0.01");return false}else{if(regAmount>10000&&currencyCode.toUpperCase()==="USD"){alert("— Oops, a slight problem: —\n\nMaximum Amount is: 10000.00");return false}else{if(!desc){alert("— Oops, a slight problem: —\n\nPlease type a Description for this Button.");return false}}}}shortCodeTemplateAttrs+='level="*" ccaps="'+esc_attr(cCaps)+'" desc="'+esc_attr(desc)+'" ps="'+esc_attr(pageStyle)+'" lc="'+esc_attr(localeCode)+'" cc="'+esc_attr(currencyCode)+'" dg="'+esc_attr(digital)+'" ns="'+esc_attr(noShipping)+'"';shortCodeTemplateAttrs+=' custom="<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"])); ?>" ra="'+esc_attr(regAmount)+'" rp="'+esc_attr(regPeriod)+'" rt="'+esc_attr(regTerm)+'" rr="'+esc_attr(regRecur)+'"';shortCode.val(shortCodeTemplate.replace(/%%attrs%%/,shortCodeTemplateAttrs));code.html(code.val().replace(/ name\="lc" value\="(.*?)"/,' name="lc" value="'+esc_attr(localeCode)+'"'));code.html(code.val().replace(/ name\="no_shipping" value\="(.*?)"/,' name="no_shipping" value="'+esc_attr(noShipping)+'"'));code.html(code.val().replace(/ name\="item_name" value\="(.*?)"/,' name="item_name" value="'+esc_attr(desc)+'"'));code.html(code.val().replace(/ name\="item_number" value\="(.*?)"/,' name="item_number" value="'+esc_attr(levelCcapsPer)+'"'));code.html(code.val().replace(/ name\="page_style" value\="(.*?)"/,' name="page_style" value="'+esc_attr(pageStyle)+'"'));code.html(code.val().replace(/ name\="currency_code" value\="(.*?)"/,' name="currency_code" value="'+esc_attr(currencyCode)+'"'));code.html(code.val().replace(/ name\="custom" value\="(.*?)"/,' name="custom" value="<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"])); ?>"'));code.html(code.val().replace(/ name\="amount" value\="(.*?)"/,' name="amount" value="'+esc_attr(regAmount)+'"'));$("div#ws-plugin--s2member-ccap-button-prev").html(code.val().replace(/\<form/,'<form target="_blank"').replace(/\<\?php echo S2MEMBER_VALUE_FOR_PP_INV\(\); \?\>/g,Math.round(new Date().getTime())+'~<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["REMOTE_ADDR"])); ?>').replace(/\<\?php echo S2MEMBER_CURRENT_USER_VALUE_FOR_PP_(ON0|OS0|ON1|OS1); \?\>/g,""));alert("Your Button has been generated.\nPlease copy/paste the Shortcode into your Login Welcome Page, or wherever you feel it would be most appropriate.\n\n* Remember, Independent Custom Capability Buttons should ONLY be displayed to existing Users/Members, and they MUST be logged-in, BEFORE clicking this Button.");shortCode.each(function(){this.focus(),this.select()});return false};ws_plugin__s2member_paypalSpButtonGenerate=function(){var shortCodeTemplate='[s2Member-PayPal-Button %%attrs%% image="default" output="button" /]',shortCodeTemplateAttrs="";var shortCode=$("input#ws-plugin--s2member-sp-shortcode");var code=$("textarea#ws-plugin--s2member-sp-button");var leading=$("select#ws-plugin--s2member-sp-leading-id").val().replace(/[^0-9]/g,"");var additionals=$("select#ws-plugin--s2member-sp-additional-ids").val()||[];var hours=$("select#ws-plugin--s2member-sp-hours").val().replace(/[^0-9]/g,"");var regAmount=$("input#ws-plugin--s2member-sp-amount").val().replace(/[^0-9\.]/g,"");var desc=$.trim($("input#ws-plugin--s2member-sp-desc").val().replace(/"/g,""));var localeCode="",digital="0",noShipping="1";var pageStyle=$.trim($("input#ws-plugin--s2member-sp-page-style").val().replace(/"/g,""));var currencyCode=$("select#ws-plugin--s2member-sp-currency").val().replace(/[^A-Z]/g,"");if(!leading){alert("— Oops, a slight problem: —\n\nPlease 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 -› Restriction Options -› Specific Post/Page Access.");return false}else{if(!regAmount||isNaN(regAmount)||regAmount<0.01){alert("— Oops, a slight problem: —\n\nAmount must be >= 0.01");return false}else{if(regAmount>10000&&currencyCode.toUpperCase()==="USD"){alert("— Oops, a slight problem: —\n\nMaximum Amount is: 10000.00");return false}else{if(!desc){alert("— Oops, a slight problem: —\n\nPlease type a Description for this Button.");return false}}}}for(var i=0,ids=leading;i<additionals.length;i++){if(additionals[i]&&additionals[i]!==leading){ids+=","+additionals[i]}}var spIdsHours="sp:"+ids+":"+hours;shortCodeTemplateAttrs+='sp="1" ids="'+esc_attr(ids)+'" exp="'+esc_attr(hours)+'" desc="'+esc_attr(desc)+'" ps="'+esc_attr(pageStyle)+'" lc="'+esc_attr(localeCode)+'" cc="'+esc_attr(currencyCode)+'" dg="'+esc_attr(digital)+'" ns="'+esc_attr(noShipping)+'"';shortCodeTemplateAttrs+=' custom="<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"])); ?>" ra="'+esc_attr(regAmount)+'"';shortCode.val(shortCodeTemplate.replace(/%%attrs%%/,shortCodeTemplateAttrs));code.html(code.val().replace(/ name\="lc" value\="(.*?)"/,' name="lc" value="'+esc_attr(localeCode)+'"'));code.html(code.val().replace(/ name\="no_shipping" value\="(.*?)"/,' name="no_shipping" value="'+esc_attr(noShipping)+'"'));code.html(code.val().replace(/ name\="item_name" value\="(.*?)"/,' name="item_name" value="'+esc_attr(desc)+'"'));code.html(code.val().replace(/ name\="item_number" value\="(.*?)"/,' name="item_number" value="'+esc_attr(spIdsHours)+'"'));code.html(code.val().replace(/ name\="page_style" value\="(.*?)"/,' name="page_style" value="'+esc_attr(pageStyle)+'"'));code.html(code.val().replace(/ name\="currency_code" value\="(.*?)"/,' name="currency_code" value="'+esc_attr(currencyCode)+'"'));code.html(code.val().replace(/ name\="custom" value\="(.*?)"/,' name="custom" value="<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"])); ?>"'));code.html(code.val().replace(/ name\="amount" value\="(.*?)"/,' name="amount" value="'+esc_attr(regAmount)+'"'));$("div#ws-plugin--s2member-sp-button-prev").html(code.val().replace(/\<form/,'<form target="_blank"').replace(/\<\?php echo S2MEMBER_VALUE_FOR_PP_INV\(\); \?\>/g,Math.round(new Date().getTime())+'~<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["REMOTE_ADDR"])); ?>').replace(/\<\?php echo S2MEMBER_CURRENT_USER_VALUE_FOR_PP_(ON0|OS0|ON1|OS1); \?\>/g,""));alert("Your Button has been generated.\nPlease copy/paste the Shortcode into your WordPress Editor.");shortCode.each(function(){this.focus(),this.select()});return false};ws_plugin__s2member_paypalRegLinkGenerate=function(){var level=$("select#ws-plugin--s2member-reg-link-level").val().replace(/[^0-9]/g,"");var subscrID=$.trim($("input#ws-plugin--s2member-reg-link-subscr-id").val());var custom=$.trim($("input#ws-plugin--s2member-reg-link-custom").val());var cCaps=$.trim($.trim($("input#ws-plugin--s2member-reg-link-ccaps").val()).replace(/[ \-]/g,"_").replace(/[^a-z_0-9,]/gi,"").toLowerCase());var fixedTerm=$.trim($("input#ws-plugin--s2member-reg-link-fixed-term").val().replace(/[^A-Z 0-9]/gi,"").toUpperCase());var $link=$("p#ws-plugin--s2member-reg-link"),$loading=$("img#ws-plugin--s2member-reg-link-loading");var levelCcapsPer=(fixedTerm&&!fixedTerm.match(/L$/))?level+":"+cCaps+":"+fixedTerm:level+":"+cCaps;levelCcapsPer=levelCcapsPer.replace(/\:+$/g,"");if(!subscrID){alert("— Oops, a slight problem: —\n\nPaid Subscr. ID is a required value.");return false}else{if(!custom||custom.indexOf('<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq ($_SERVER["HTTP_HOST"]); ?>')!==0){alert("— Oops, a slight problem: —\n\nThe Custom Value MUST start with your domain name.");return false}else{if(fixedTerm&&!fixedTerm.match(/^[1-9]+ (D|W|M|Y|L)$/)){alert("— Oops, a slight problem: —\n\nThe Fixed Term Length is not formatted properly.");return false}}}$link.hide(),$loading.show(),$.post(ajaxurl,{action:"ws_plugin__s2member_reg_access_link_via_ajax",ws_plugin__s2member_reg_access_link_via_ajax:'<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (wp_create_nonce ("ws-plugin--s2member-reg-access-link-via-ajax")); ?>',s2member_reg_access_link_subscr_gateway:"paypal",s2member_reg_access_link_subscr_id:subscrID,s2member_reg_access_link_custom:custom,s2member_reg_access_link_item_number:levelCcapsPer},function(response){$link.show().html('<a href="'+esc_attr(response)+'" target="_blank" rel="external">'+esc_html(response)+"</a>"),$loading.hide()});return false};ws_plugin__s2member_paypalSpLinkGenerate=function(){var leading=$("select#ws-plugin--s2member-sp-link-leading-id").val().replace(/[^0-9]/g,"");var additionals=$("select#ws-plugin--s2member-sp-link-additional-ids").val()||[];var hours=$("select#ws-plugin--s2member-sp-link-hours").val().replace(/[^0-9]/g,"");var $link=$("p#ws-plugin--s2member-sp-link"),$loading=$("img#ws-plugin--s2member-sp-link-loading");if(!leading){alert("— Oops, a slight problem: —\n\nPlease 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 -› Restriction Options -› Specific Post/Page Access.");return false}for(var i=0,ids=leading;i<additionals.length;i++){if(additionals[i]&&additionals[i]!==leading){ids+=","+additionals[i]}}$link.hide(),$loading.show(),$.post(ajaxurl,{action:"ws_plugin__s2member_sp_access_link_via_ajax",ws_plugin__s2member_sp_access_link_via_ajax:'<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (wp_create_nonce ("ws-plugin--s2member-sp-access-link-via-ajax")); ?>',s2member_sp_access_link_ids:ids,s2member_sp_access_link_hours:hours},function(response){$link.show().html('<a href="'+esc_attr(response)+'" target="_blank" rel="external">'+esc_html(response)+"</a>"),$loading.hide()});return false}}if(location.href.match(/page\=ws-plugin--s2member-els-ops/)){$("select#ws-plugin--s2member-custom-reg-opt-in").change(function(){var $this=$(this),val=$this.val();var $rows=$("tr.ws-plugin--s2member-custom-reg-opt-in-label-row");var $prevImg=$("img.ws-plugin--s2member-custom-reg-opt-in-label-prev-img");if(val<=0){$rows.css("display","none"),$prevImg.attr("src",$prevImg.attr("src").replace(/\/checked\.png$/,"/unchecked.png"))}else{if(val==1){$rows.css("display",""),$prevImg.attr("src",$prevImg.attr("src").replace(/\/unchecked\.png$/,"/checked.png"))}else{if(val==2){$rows.css("display",""),$prevImg.attr("src",$prevImg.attr("src").replace(/\/checked\.png$/,"/unchecked.png"))}}}});$('div.ws-plugin--s2member-opt-out-section input[type="checkbox"][name="ws_plugin__s2member_custom_reg_auto_opt_outs[]"]').change(function(){var thisChange=$(this).val(),checkedIndexes=[];$('div.ws-plugin--s2member-opt-out-section input[type="checkbox"][name="ws_plugin__s2member_custom_reg_auto_opt_outs[]"]').each(function(){var $this=$(this),val=$this.val(),checkboxes='input[type="checkbox"]';if(val==="removal-deletion"&&this.checked){$this.nextAll(checkboxes).slice(0,2).attr({checked:"checked",disabled:"disabled"})}else{if(val==="removal-deletion"&&!this.checked){$this.nextAll(checkboxes).slice(0,2).removeAttr("disabled");(thisChange==="removal-deletion")?$this.nextAll(checkboxes).slice(0,2).removeAttr("checked"):null}else{if(val==="modification"&&this.checked){$this.nextAll(checkboxes).slice(0,3).attr({checked:"checked",disabled:"disabled"})}else{if(val==="modification"&&!this.checked){(thisChange==="modification")?$this.nextAll(checkboxes).slice(0,3).removeAttr("checked"):null;$this.nextAll(checkboxes).slice(0,3).removeAttr("disabled")}}}}}).each(function(index){(this.checked)?checkedIndexes.push(index):null});$("select#ws-plugin--s2member-custom-reg-auto-opt-out-transitions").removeAttr("disabled");if($.inArray(3,checkedIndexes)===-1&&$.inArray(4,checkedIndexes)===-1&&$.inArray(5,checkedIndexes)===-1&&$.inArray(6,checkedIndexes)===-1){$("select#ws-plugin--s2member-custom-reg-auto-opt-out-transitions").attr("disabled","disabled")}}).last().trigger("change")}});
includes/menu-pages/menu-pages-s.js CHANGED
@@ -19,7 +19,7 @@ jQuery(document).ready(function($)
19
  {
20
  return String(str).replace(/"/g, '&quot;').replace(/\</g, '&lt;').replace(/\>/g, '&gt;');
21
  };
22
- if(location.href.match /* Any & all s2Member® pages. */(/page\=ws-plugin--s2member/))
23
  {
24
  $('input.ws-plugin--s2member-update-roles-button, input.ws-plugin--s2member-reset-roles-button').click(function()
25
  {
@@ -873,12 +873,12 @@ jQuery(document).ready(function($)
873
 
874
  if(autoConfigDistrosStatusValue === 'configured' && ((visiblePrivateKeyIdPrevConfigValue && visiblePrivateKeyIdValue !== visiblePrivateKeyIdPrevConfigValue) || (hiddenPrivateKeyPrevConfigValue && hiddenPrivateKeyValue !== hiddenPrivateKeyPrevConfigValue)))
875
  {
876
- alert('s2Member will need to delete and re-configure your Amazon® CloudFront distributions if you change this. When you\'re done editing, click (Save All Changes) below.');
877
  $autoConfigDistros.attr /* Forcibly check. */('checked', 'checked');
878
  }
879
  else if(autoConfigDistrosStatusValue !== 'configured' && visiblePrivateKeyIdValue && hiddenPrivateKeyValue)
880
  {
881
- alert('s2Member will need to auto-configure your Amazon® CloudFront distributions for you. When you\'re done editing, click (Save All Changes) below.');
882
  $autoConfigDistros.attr /* Forcibly check. */('checked', 'checked');
883
  }
884
  };
@@ -937,7 +937,7 @@ jQuery(document).ready(function($)
937
  if /* Only if there is a problem with the actual values; because this causes interruptions. */(value.match(/[^a-z_0-9,]/))
938
  this.value = _all+$.trim($.trim(value).replace(/[ \-]/g, '_').replace(/[^a-z_0-9,]/gi, '').toLowerCase());
939
  });
940
- ws_plugin__s2member_paypalButtonGenerate = /* Handles PayPal® Button Generation. */ function(button)
941
  {
942
  var shortCodeTemplate = '[s2Member-PayPal-Button %%attrs%% image="default" output="button" /]', shortCodeTemplateAttrs = '', labels = {};
943
 
@@ -1064,7 +1064,7 @@ jQuery(document).ready(function($)
1064
  });
1065
  return false;
1066
  };
1067
- ws_plugin__s2member_paypalCcapButtonGenerate = /* Handles PayPal® Button Generation for Independent Capabilities. */ function()
1068
  {
1069
  var shortCodeTemplate = '[s2Member-PayPal-Button %%attrs%% image="default" output="button" /]', shortCodeTemplateAttrs = '';
1070
 
@@ -1133,7 +1133,7 @@ jQuery(document).ready(function($)
1133
  });
1134
  return false;
1135
  };
1136
- ws_plugin__s2member_paypalSpButtonGenerate = /* Handles PayPal® Button Generation for Specific Post/Page Access. */ function()
1137
  {
1138
  var shortCodeTemplate = '[s2Member-PayPal-Button %%attrs%% image="default" output="button" /]', shortCodeTemplateAttrs = '';
1139
 
@@ -1193,7 +1193,7 @@ jQuery(document).ready(function($)
1193
 
1194
  $('div#ws-plugin--s2member-sp-button-prev').html(code.val().replace(/\<form/, '<form target="_blank"').replace(/\<\?php echo S2MEMBER_VALUE_FOR_PP_INV\(\); \?\>/g, Math.round(new Date().getTime())+'~<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["REMOTE_ADDR"])); ?>').replace(/\<\?php echo S2MEMBER_CURRENT_USER_VALUE_FOR_PP_(ON0|OS0|ON1|OS1); \?\>/g, ''));
1195
 
1196
- alert('Your Button has been generated.\nPlease copy/paste the Shortcode into your WordPress® Editor.');
1197
 
1198
  shortCode.each( /* Focus and select the Shortcode. */function()
1199
  {
@@ -1201,7 +1201,7 @@ jQuery(document).ready(function($)
1201
  });
1202
  return false;
1203
  };
1204
- ws_plugin__s2member_paypalRegLinkGenerate = /* Handles PayPal® Link Generation. */ function()
1205
  {
1206
  var level = $('select#ws-plugin--s2member-reg-link-level').val().replace(/[^0-9]/g, '');
1207
  var subscrID = $.trim($('input#ws-plugin--s2member-reg-link-subscr-id').val());
@@ -1234,7 +1234,7 @@ jQuery(document).ready(function($)
1234
  });
1235
  return false;
1236
  };
1237
- ws_plugin__s2member_paypalSpLinkGenerate = /* Handles PayPal® Link Generation. */ function()
1238
  {
1239
  var leading = $('select#ws-plugin--s2member-sp-link-leading-id').val().replace(/[^0-9]/g, '');
1240
  var additionals = $('select#ws-plugin--s2member-sp-link-additional-ids').val() || [];
19
  {
20
  return String(str).replace(/"/g, '&quot;').replace(/\</g, '&lt;').replace(/\>/g, '&gt;');
21
  };
22
+ if(location.href.match /* Any & all s2Member pages. */(/page\=ws-plugin--s2member/))
23
  {
24
  $('input.ws-plugin--s2member-update-roles-button, input.ws-plugin--s2member-reset-roles-button').click(function()
25
  {
873
 
874
  if(autoConfigDistrosStatusValue === 'configured' && ((visiblePrivateKeyIdPrevConfigValue && visiblePrivateKeyIdValue !== visiblePrivateKeyIdPrevConfigValue) || (hiddenPrivateKeyPrevConfigValue && hiddenPrivateKeyValue !== hiddenPrivateKeyPrevConfigValue)))
875
  {
876
+ alert('s2Member will need to delete and re-configure your Amazon CloudFront distributions if you change this. When you\'re done editing, click (Save All Changes) below.');
877
  $autoConfigDistros.attr /* Forcibly check. */('checked', 'checked');
878
  }
879
  else if(autoConfigDistrosStatusValue !== 'configured' && visiblePrivateKeyIdValue && hiddenPrivateKeyValue)
880
  {
881
+ alert('s2Member will need to auto-configure your Amazon CloudFront distributions for you. When you\'re done editing, click (Save All Changes) below.');
882
  $autoConfigDistros.attr /* Forcibly check. */('checked', 'checked');
883
  }
884
  };
937
  if /* Only if there is a problem with the actual values; because this causes interruptions. */(value.match(/[^a-z_0-9,]/))
938
  this.value = _all+$.trim($.trim(value).replace(/[ \-]/g, '_').replace(/[^a-z_0-9,]/gi, '').toLowerCase());
939
  });
940
+ ws_plugin__s2member_paypalButtonGenerate = /* Handles PayPal Button Generation. */ function(button)
941
  {
942
  var shortCodeTemplate = '[s2Member-PayPal-Button %%attrs%% image="default" output="button" /]', shortCodeTemplateAttrs = '', labels = {};
943
 
1064
  });
1065
  return false;
1066
  };
1067
+ ws_plugin__s2member_paypalCcapButtonGenerate = /* Handles PayPal Button Generation for Independent Capabilities. */ function()
1068
  {
1069
  var shortCodeTemplate = '[s2Member-PayPal-Button %%attrs%% image="default" output="button" /]', shortCodeTemplateAttrs = '';
1070
 
1133
  });
1134
  return false;
1135
  };
1136
+ ws_plugin__s2member_paypalSpButtonGenerate = /* Handles PayPal Button Generation for Specific Post/Page Access. */ function()
1137
  {
1138
  var shortCodeTemplate = '[s2Member-PayPal-Button %%attrs%% image="default" output="button" /]', shortCodeTemplateAttrs = '';
1139
 
1193
 
1194
  $('div#ws-plugin--s2member-sp-button-prev').html(code.val().replace(/\<form/, '<form target="_blank"').replace(/\<\?php echo S2MEMBER_VALUE_FOR_PP_INV\(\); \?\>/g, Math.round(new Date().getTime())+'~<?php echo c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["REMOTE_ADDR"])); ?>').replace(/\<\?php echo S2MEMBER_CURRENT_USER_VALUE_FOR_PP_(ON0|OS0|ON1|OS1); \?\>/g, ''));
1195
 
1196
+ alert('Your Button has been generated.\nPlease copy/paste the Shortcode into your WordPress Editor.');
1197
 
1198
  shortCode.each( /* Focus and select the Shortcode. */function()
1199
  {
1201
  });
1202
  return false;
1203
  };
1204
+ ws_plugin__s2member_paypalRegLinkGenerate = /* Handles PayPal Link Generation. */ function()
1205
  {
1206
  var level = $('select#ws-plugin--s2member-reg-link-level').val().replace(/[^0-9]/g, '');
1207
  var subscrID = $.trim($('input#ws-plugin--s2member-reg-link-subscr-id').val());
1234
  });
1235
  return false;
1236
  };
1237
+ ws_plugin__s2member_paypalSpLinkGenerate = /* Handles PayPal Link Generation. */ function()
1238
  {
1239
  var leading = $('select#ws-plugin--s2member-sp-link-leading-id').val().replace(/[^0-9]/g, '');
1240
  var additionals = $('select#ws-plugin--s2member-sp-link-additional-ids').val() || [];
includes/menu-pages/menu-pages.css CHANGED
@@ -1,7 +1,7 @@
1
  /**
2
  * Core CSS stylesheet for administrative menu pages.
3
  *
4
- * This file is included with all WordPress® themes/plugins by WebSharks, Inc.
5
  *
6
  * Copyright: © 2009-2011
7
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -54,7 +54,7 @@ div.ws-menu-page div.ws-menu-page-hr
54
  height: 1px;
55
  line-height: 1px;
56
  background: #DDDDDD;
57
- margin: 20px 0 20px 0;
58
  }
59
  div.ws-menu-page .ws-menu-page-hilite
60
  {
@@ -147,10 +147,12 @@ table.ws-menu-page-table ol
147
  table.ws-menu-page-table ul > li
148
  {
149
  list-style: disc outside;
 
150
  }
151
  table.ws-menu-page-table ol > li
152
  {
153
  list-style: decimal outside;
 
154
  }
155
  table.ws-menu-page-table > tbody > tr
156
  {
@@ -201,14 +203,13 @@ table.ws-menu-page-table div.ws-menu-page-groups-hide
201
  height: 24px;
202
  width: 24px;
203
  color: #333333;
204
- padding: 10px;
205
  cursor: pointer;
206
  font-size: 28px;
207
  font-weight: bold;
208
- line-height: 24px;
209
  text-align: center;
210
- background: #FFFFFF;
211
- margin: 0 0 0 20px;
212
  vertical-align: middle;
213
  font-family: monospace;
214
  border: 1px solid #666666;
@@ -218,6 +219,7 @@ table.ws-menu-page-table div.ws-menu-page-groups-hide
218
  -moz-user-select: none;
219
  -webkit-user-select: none;
220
  user-select: none;
 
221
  }
222
  table.ws-menu-page-table div.ws-menu-page-groups-hide
223
  {
@@ -229,13 +231,12 @@ table.ws-menu-page-table div.ws-menu-page-r-group-header
229
  {
230
  height: 24px;
231
  color: #666666;
232
- padding: 10px;
233
  cursor: pointer;
234
  font-size: 19px;
235
- line-height: 24px;
236
  position: relative;
237
- background: #FFFFFF;
238
- margin: 30px 0 30px 0;
239
  vertical-align: middle;
240
  font-family: 'Georgia', serif;
241
  border: 1px solid #CCCCCC;
@@ -245,6 +246,7 @@ table.ws-menu-page-table div.ws-menu-page-r-group-header
245
  -moz-user-select: none;
246
  -webkit-user-select: none;
247
  user-select: none;
 
248
  }
249
  table.ws-menu-page-table div.ws-menu-page-group-header > ins,
250
  table.ws-menu-page-table div.ws-menu-page-r-group-header > ins
@@ -291,7 +293,7 @@ table.ws-menu-page-table div.ws-menu-page-group,
291
  table.ws-menu-page-table div.ws-menu-page-r-group
292
  {
293
  display: none;
294
- margin: -35px 5px 0 5px;
295
  padding: 20px 10px 10px 10px;
296
  border: 1px solid #CCCCCC;
297
  -moz-border-radius: 5px;
@@ -314,13 +316,13 @@ table.ws-menu-page-table div.ws-menu-page-group table.form-table > tbody > tr >
314
  width: auto;
315
  color: #164A61;
316
  font-size: 115%;
317
- padding: 10px 10px 0 0;
318
  font-family: 'Georgia', serif;
319
  }
320
  table.ws-menu-page-table div.ws-menu-page-group table.form-table > tbody > tr > td
321
  {
322
  width: auto;
323
- padding: 8px 10px 8px 0;
324
  }
325
  table.ws-menu-page-table div.ws-menu-page-group table.form-table > tbody > tr > th.ws-menu-page-th-side
326
  {
@@ -396,10 +398,12 @@ div.ws-menu-page-readme > div.readme > div.section > div.content ol
396
  div.ws-menu-page-readme > div.readme > div.section > div.content ul > li
397
  {
398
  list-style: disc outside;
 
399
  }
400
  div.ws-menu-page-readme > div.readme > div.section > div.content ol > li
401
  {
402
  list-style: decimal outside;
 
403
  }
404
  /*
405
  Specifically for the right sidebar panel.
1
  /**
2
  * Core CSS stylesheet for administrative menu pages.
3
  *
4
+ * This file is included with all WordPress themes/plugins by WebSharks, Inc.
5
  *
6
  * Copyright: © 2009-2011
7
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
54
  height: 1px;
55
  line-height: 1px;
56
  background: #DDDDDD;
57
+ margin: 7px 0 7px 0;
58
  }
59
  div.ws-menu-page .ws-menu-page-hilite
60
  {
147
  table.ws-menu-page-table ul > li
148
  {
149
  list-style: disc outside;
150
+ margin-bottom: 0;
151
  }
152
  table.ws-menu-page-table ol > li
153
  {
154
  list-style: decimal outside;
155
+ margin-bottom: 0;
156
  }
157
  table.ws-menu-page-table > tbody > tr
158
  {
203
  height: 24px;
204
  width: 24px;
205
  color: #333333;
206
+ padding: 5px;
207
  cursor: pointer;
208
  font-size: 28px;
209
  font-weight: bold;
210
+ line-height: 25px;
211
  text-align: center;
212
+ margin: 0 0 0 7px;
 
213
  vertical-align: middle;
214
  font-family: monospace;
215
  border: 1px solid #666666;
219
  -moz-user-select: none;
220
  -webkit-user-select: none;
221
  user-select: none;
222
+ background: linear-gradient(to bottom, #FFFFFF 95%, rgba(236, 236, 236, 1) 90%);
223
  }
224
  table.ws-menu-page-table div.ws-menu-page-groups-hide
225
  {
231
  {
232
  height: 24px;
233
  color: #666666;
234
+ padding: 5px;
235
  cursor: pointer;
236
  font-size: 19px;
237
+ line-height: 20px;
238
  position: relative;
239
+ margin: 7px 0 7px 0;
 
240
  vertical-align: middle;
241
  font-family: 'Georgia', serif;
242
  border: 1px solid #CCCCCC;
246
  -moz-user-select: none;
247
  -webkit-user-select: none;
248
  user-select: none;
249
+ background: linear-gradient(to bottom, #FFFFFF 95%, rgba(236, 236, 236, 1) 90%);
250
  }
251
  table.ws-menu-page-table div.ws-menu-page-group-header > ins,
252
  table.ws-menu-page-table div.ws-menu-page-r-group-header > ins
293
  table.ws-menu-page-table div.ws-menu-page-r-group
294
  {
295
  display: none;
296
+ margin: -15px 5px 0 5px;
297
  padding: 20px 10px 10px 10px;
298
  border: 1px solid #CCCCCC;
299
  -moz-border-radius: 5px;
316
  width: auto;
317
  color: #164A61;
318
  font-size: 115%;
319
+ padding: 0 0.5em 0 0;
320
  font-family: 'Georgia', serif;
321
  }
322
  table.ws-menu-page-table div.ws-menu-page-group table.form-table > tbody > tr > td
323
  {
324
  width: auto;
325
+ padding: 0.5em 10px 0.5em 0;
326
  }
327
  table.ws-menu-page-table div.ws-menu-page-group table.form-table > tbody > tr > th.ws-menu-page-th-side
328
  {
398
  div.ws-menu-page-readme > div.readme > div.section > div.content ul > li
399
  {
400
  list-style: disc outside;
401
+ margin-bottom: 0;
402
  }
403
  div.ws-menu-page-readme > div.readme > div.section > div.content ol > li
404
  {
405
  list-style: decimal outside;
406
+ margin-bottom: 0;
407
  }
408
  /*
409
  Specifically for the right sidebar panel.
includes/menu-pages/menu-pages.js CHANGED
@@ -4,7 +4,7 @@
4
  * This is the development version of the code.
5
  * Which ultimately produces menu-pages-min.js.
6
  *
7
- * This file is included with all WordPress® themes/plugins by WebSharks, Inc.
8
  *
9
  * Copyright: © 2009-2011
10
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
4
  * This is the development version of the code.
5
  * Which ultimately produces menu-pages-min.js.
6
  *
7
+ * This file is included with all WordPress themes/plugins by WebSharks, Inc.
8
  *
9
  * Copyright: © 2009-2011
10
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
includes/menu-pages/mms-ops.inc.php CHANGED
@@ -32,7 +32,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_mms_ops"))
32
  echo '<div class="wrap ws-menu-page">'."\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>'."\n";
35
- echo '<h2>s2Member® Multisite (Configuration)</h2>'."\n";
36
 
37
  echo '<table class="ws-menu-page-table">'."\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">'."\n";
@@ -51,11 +51,11 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_mms_ops"))
51
  {
52
  do_action("ws_plugin__s2member_during_mms_ops_page_during_left_sections_before_mms_patches", get_defined_vars());
53
 
54
- echo '<div class="ws-menu-page-group" title="Multisite WordPress® Patches" default-state="open">'."\n";
55
 
56
  echo '<div class="ws-menu-page-section ws-plugin--s2member-mms-patches-section">'."\n";
57
- echo '<img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/small-icon.png" title="s2Member (a Membership management system for WordPress®)" alt="" style="float:right; margin:0 0 0 25px; border:0;" />'."\n";
58
- echo '<h3>Multisite WordPress® Patches (required for compatiblity)</h3>'."\n";
59
  echo '<p>In order for s2Member to function properly in a Multisite environment, you MUST implement four patches. One goes into your <code>/wp-login.php</code> file, one into <code>/wp-includes/load.php</code>, one into <code>/wp-includes/ms-functions.php</code>, and another into <code>/wp-admin/user-new.php</code>. Please use the automatic patcher below. All you do is check the box &amp; click Save.</p>'."\n";
60
  do_action("ws_plugin__s2member_during_mms_ops_page_during_left_sections_during_mms_patches", get_defined_vars());
61
 
@@ -77,17 +77,17 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_mms_ops"))
77
  if(defined("DISALLOW_FILE_MODS") && DISALLOW_FILE_MODS)
78
  {
79
  echo '<select name="ws_plugin__s2member_mms_auto_patch" id="ws-plugin--s2member-mms-auto-patch" disabled="disabled">'."\n";
80
- echo '<option value="0" selected="selected">No (I\'ll patch WordPress® myself)</option>'."\n";
81
  echo '</select><br />'."\n";
82
  echo '<em class="ws-menu-page-hilite">This is now locked. Your <code>/wp-config.php</code> file says: <code>DISALLOW_FILE_MODS = true</code></em>.'."\n";
83
  }
84
  else // Otherwise we can display these options.
85
  {
86
  echo '<select name="ws_plugin__s2member_mms_auto_patch" id="ws-plugin--s2member-mms-auto-patch">'."\n";
87
- echo '<option value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["mms_auto_patch"]) ? ' selected="selected"' : '').'>Yes (automatically patch WordPress®)</option>'."\n";
88
- echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["mms_auto_patch"]) ? ' selected="selected"' : '').'>No (I\'ll patch WordPress® myself)</option>'."\n";
89
  echo '</select><br />'."\n";
90
- echo '<em class="ws-menu-page-hilite">These files MUST be patched, each time you upgrade the WordPress® core. If you set this option to <code>Yes (Patch Automatically)</code>, s2Member will patch your installation now, and also in the future, should you upgrade to newer version. That way, you won\'t need to patch manually each time WordPress® is upgraded.</em>'."\n";
91
  }
92
 
93
  echo '</td>'."\n";
@@ -109,7 +109,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_mms_ops"))
109
  echo '<p>'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/mms-patch-user-new.x-php")).'</p>'."\n";
110
  echo '<p><strong>Patch #4</strong> ( /wp-includes/ms-functions.php )</p>'."\n";
111
  echo '<p>'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/mms-patch-ms-functions.x-php")).'</p>'."\n";
112
- echo '<p><em class="ws-menu-page-hilite">Don\'t forget to patch these files again, each time you upgrade the WordPress® core.</em></p>'."\n";
113
  echo '</div>'."\n";
114
  echo '</div>'."\n";
115
  echo '</div>'."\n";
@@ -126,12 +126,12 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_mms_ops"))
126
  echo '<div class="ws-menu-page-group" title="Multisite Registration Configuration" default-state="open">'."\n";
127
 
128
  echo '<div class="ws-menu-page-section ws-plugin--s2member-mms-registration-section">'."\n";
129
- echo '<img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/large-icon.png" title="s2Member (a Membership management system for WordPress®)" alt="" style="float:right; margin:0 0 0 25px; border:0;" />'."\n";
130
  echo '<h3>Multisite Registration (Main Site Configuration)</h3>'."\n";
131
  echo '<p>s2Member supports Free Subscribers <em>(at Level #0)</em>, and several Primary Roles created by the s2Member plugin (<em> i.e. s2Member Levels 1-4, or up to the number of configured Levels )</em>. If you want your visitors to be capable of registering absolutely free, you will want to "allow" Open Registration. Whenever a visitor registers without paying, they\'ll automatically become a Free Subscriber, at Level #0.</p>'."\n";
132
  echo '<p><strong>Running A Multisite Blog Farm?</strong> With Multisite Networking enabled, your Main Site could ALSO offer a Customer access to create a Blog of their own <em>(optional)</em>, where a Customer becomes a "Member" of your Main Site, and also a Blog Owner/Administrator of at least one other Blog on your Network. With s2Member installed <em>(Network wide)</em>, each of your Blog Owners could offer Membership too, using a single copy of the s2Member plugin, which is a great selling point<em>!</em> We refer to this type of installation as a Multisite Blog Farm.</p>'."\n";
133
  echo '<p>Multisite Networking makes a new Registration Form available <em>(driven by your theme)</em>; which we refer to as: <code>/wp-signup.php</code>. If, and only if, you\'re planning to offer Blogs, you MUST use <a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::wp_signup_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your Multisite Registration Form.\\n* s2Member makes this form available to logged-in Super Administrators, at all times (for testing purposes), regardless of configuration.'.((c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '\\n\\nBuddyPress: * BuddyPress will use its own Registration Form. Please note, you will probably be redirected away from the BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re ALREADY logged-in. Please log out before testing BuddyPress registration.' : '').'\');">/wp-signup.php</a>, instead of using the Standard Login/Registration Form. In a Multisite installation, we refer to the Standard Login/Registration Form, as: <a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::wp_register_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your Standard Registration Form.\\n* s2Member makes this form available to logged-in Administrators, at all times (for testing purposes), regardless of configuration.'.((c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '\\n\\nBuddyPress: * BuddyPress will use its own Registration Form. Please note, you will probably be redirected away from the BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re ALREADY logged-in. Please log out before testing BuddyPress registration.' : '').'\');">/wp-login.php?action=register</a>. If you\'re planning to offer Membership Access only, and NOT Blogs, you can simply use the <a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::wp_register_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your Standard Registration Form.\\n* s2Member makes this form available to logged-in Administrators, at all times (for testing purposes), regardless of configuration.'.((c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '\\n\\nBuddyPress: * BuddyPress will use its own Registration Form. Please note, you will probably be redirected away from the BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re ALREADY logged-in. Please log out before testing BuddyPress registration.' : '').'\');">Standard Login/Registration Form</a>, which is easily customized through <code>s2Member -› General Options -› Login/Registration Design</code>.</p>'."\n";
134
- echo '<p>In either case, s2Member Pro Forms are possible too. If you\'ve purchased s2Member Pro, you could use Pro Forms instead of these WordPress® defaults. That being said, even with s2Member Pro Forms, if you are offering Blogs, you will still need to facilitate the actual creation of each Blog through <code>/wp-signup.php</code>. In other words, Customers can register through s2Member Pro Forms, and even checkout. But when it comes time to setup a new Blog, you will need to redirect your Customer to <code>/wp-signup.php</code>, while they are logged-in. This will allow them to create a new Blog on your Network. That is, if they are allowed to <em>(based on your configuration below)</em>.</p>'."\n";
135
  echo (c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '<p><em><strong>BuddyPress:</strong> BuddyPress will use its own Registration Form, powered by your theme.<br />(BuddyPress can handle both Membership and Blog creation in its integration)<br />(<a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::bp_register_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your BuddyPress Registration Form.\\n* However, you will probably be redirected away from this BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re ALREADY logged-in. Please log out before testing BuddyPress registration.\');">'.esc_html(c_ws_plugin__s2member_utils_urls::bp_register_url()).'</a>)</em></p>'."\n" : '';
136
  do_action("ws_plugin__s2member_during_mms_ops_page_during_left_sections_during_mms_registration", get_defined_vars());
137
 
@@ -303,8 +303,8 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_mms_ops"))
303
  }
304
  else // Otherwise, we can display a simple notation; leading into Multisite Networking.
305
  {
306
- echo '<p style="margin-top:0;"><span class="ws-menu-page-hilite">Your WordPress® installation does not have Multisite Networking enabled.<br />Which is perfectly OK :-) Multisite Networking is 100% completely optional.</span></p>'."\n";
307
- echo '<img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/large-icon.png" title="s2Member (a Membership management system for WordPress®)" alt="" style="float:right; margin:0 0 0 25px; border:0;" />'."\n";
308
 
309
  if(file_exists($ws_plugin__s2member_temp = dirname(dirname(dirname(__FILE__)))."/readme-ms.txt"))
310
  {
32
  echo '<div class="wrap ws-menu-page">'."\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>'."\n";
35
+ echo '<h2>s2Member Multisite (Configuration)</h2>'."\n";
36
 
37
  echo '<table class="ws-menu-page-table">'."\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">'."\n";
51
  {
52
  do_action("ws_plugin__s2member_during_mms_ops_page_during_left_sections_before_mms_patches", get_defined_vars());
53
 
54
+ echo '<div class="ws-menu-page-group" title="Multisite WordPress Patches" default-state="open">'."\n";
55
 
56
  echo '<div class="ws-menu-page-section ws-plugin--s2member-mms-patches-section">'."\n";
57
+ echo '<img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/small-icon.png" title="s2Member (a Membership management system for WordPress)" alt="" style="float:right; margin:0 0 0 25px; border:0;" />'."\n";
58
+ echo '<h3>Multisite WordPress Patches (required for compatiblity)</h3>'."\n";
59
  echo '<p>In order for s2Member to function properly in a Multisite environment, you MUST implement four patches. One goes into your <code>/wp-login.php</code> file, one into <code>/wp-includes/load.php</code>, one into <code>/wp-includes/ms-functions.php</code>, and another into <code>/wp-admin/user-new.php</code>. Please use the automatic patcher below. All you do is check the box &amp; click Save.</p>'."\n";
60
  do_action("ws_plugin__s2member_during_mms_ops_page_during_left_sections_during_mms_patches", get_defined_vars());
61
 
77
  if(defined("DISALLOW_FILE_MODS") && DISALLOW_FILE_MODS)
78
  {
79
  echo '<select name="ws_plugin__s2member_mms_auto_patch" id="ws-plugin--s2member-mms-auto-patch" disabled="disabled">'."\n";
80
+ echo '<option value="0" selected="selected">No (I\'ll patch WordPress myself)</option>'."\n";
81
  echo '</select><br />'."\n";
82
  echo '<em class="ws-menu-page-hilite">This is now locked. Your <code>/wp-config.php</code> file says: <code>DISALLOW_FILE_MODS = true</code></em>.'."\n";
83
  }
84
  else // Otherwise we can display these options.
85
  {
86
  echo '<select name="ws_plugin__s2member_mms_auto_patch" id="ws-plugin--s2member-mms-auto-patch">'."\n";
87
+ echo '<option value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["mms_auto_patch"]) ? ' selected="selected"' : '').'>Yes (automatically patch WordPress)</option>'."\n";
88
+ echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["mms_auto_patch"]) ? ' selected="selected"' : '').'>No (I\'ll patch WordPress myself)</option>'."\n";
89
  echo '</select><br />'."\n";
90
+ echo '<em class="ws-menu-page-hilite">These files MUST be patched, each time you upgrade the WordPress core. If you set this option to <code>Yes (Patch Automatically)</code>, s2Member will patch your installation now, and also in the future, should you upgrade to newer version. That way, you won\'t need to patch manually each time WordPress is upgraded.</em>'."\n";
91
  }
92
 
93
  echo '</td>'."\n";
109
  echo '<p>'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/mms-patch-user-new.x-php")).'</p>'."\n";
110
  echo '<p><strong>Patch #4</strong> ( /wp-includes/ms-functions.php )</p>'."\n";
111
  echo '<p>'.c_ws_plugin__s2member_utils_strings::highlight_php(file_get_contents(dirname(__FILE__)."/code-samples/mms-patch-ms-functions.x-php")).'</p>'."\n";
112
+ echo '<p><em class="ws-menu-page-hilite">Don\'t forget to patch these files again, each time you upgrade the WordPress core.</em></p>'."\n";
113
  echo '</div>'."\n";
114
  echo '</div>'."\n";
115
  echo '</div>'."\n";
126
  echo '<div class="ws-menu-page-group" title="Multisite Registration Configuration" default-state="open">'."\n";
127
 
128
  echo '<div class="ws-menu-page-section ws-plugin--s2member-mms-registration-section">'."\n";
129
+ echo '<img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/large-icon.png" title="s2Member (a Membership management system for WordPress)" alt="" style="float:right; margin:0 0 0 25px; border:0;" />'."\n";
130
  echo '<h3>Multisite Registration (Main Site Configuration)</h3>'."\n";
131
  echo '<p>s2Member supports Free Subscribers <em>(at Level #0)</em>, and several Primary Roles created by the s2Member plugin (<em> i.e. s2Member Levels 1-4, or up to the number of configured Levels )</em>. If you want your visitors to be capable of registering absolutely free, you will want to "allow" Open Registration. Whenever a visitor registers without paying, they\'ll automatically become a Free Subscriber, at Level #0.</p>'."\n";
132
  echo '<p><strong>Running A Multisite Blog Farm?</strong> With Multisite Networking enabled, your Main Site could ALSO offer a Customer access to create a Blog of their own <em>(optional)</em>, where a Customer becomes a "Member" of your Main Site, and also a Blog Owner/Administrator of at least one other Blog on your Network. With s2Member installed <em>(Network wide)</em>, each of your Blog Owners could offer Membership too, using a single copy of the s2Member plugin, which is a great selling point<em>!</em> We refer to this type of installation as a Multisite Blog Farm.</p>'."\n";
133
  echo '<p>Multisite Networking makes a new Registration Form available <em>(driven by your theme)</em>; which we refer to as: <code>/wp-signup.php</code>. If, and only if, you\'re planning to offer Blogs, you MUST use <a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::wp_signup_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your Multisite Registration Form.\\n* s2Member makes this form available to logged-in Super Administrators, at all times (for testing purposes), regardless of configuration.'.((c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '\\n\\nBuddyPress: * BuddyPress will use its own Registration Form. Please note, you will probably be redirected away from the BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re ALREADY logged-in. Please log out before testing BuddyPress registration.' : '').'\');">/wp-signup.php</a>, instead of using the Standard Login/Registration Form. In a Multisite installation, we refer to the Standard Login/Registration Form, as: <a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::wp_register_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your Standard Registration Form.\\n* s2Member makes this form available to logged-in Administrators, at all times (for testing purposes), regardless of configuration.'.((c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '\\n\\nBuddyPress: * BuddyPress will use its own Registration Form. Please note, you will probably be redirected away from the BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re ALREADY logged-in. Please log out before testing BuddyPress registration.' : '').'\');">/wp-login.php?action=register</a>. If you\'re planning to offer Membership Access only, and NOT Blogs, you can simply use the <a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::wp_register_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your Standard Registration Form.\\n* s2Member makes this form available to logged-in Administrators, at all times (for testing purposes), regardless of configuration.'.((c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '\\n\\nBuddyPress: * BuddyPress will use its own Registration Form. Please note, you will probably be redirected away from the BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re ALREADY logged-in. Please log out before testing BuddyPress registration.' : '').'\');">Standard Login/Registration Form</a>, which is easily customized through <code>s2Member -› General Options -› Login/Registration Design</code>.</p>'."\n";
134
+ echo '<p>In either case, s2Member Pro Forms are possible too. If you\'ve purchased s2Member Pro, you could use Pro Forms instead of these WordPress defaults. That being said, even with s2Member Pro Forms, if you are offering Blogs, you will still need to facilitate the actual creation of each Blog through <code>/wp-signup.php</code>. In other words, Customers can register through s2Member Pro Forms, and even checkout. But when it comes time to setup a new Blog, you will need to redirect your Customer to <code>/wp-signup.php</code>, while they are logged-in. This will allow them to create a new Blog on your Network. That is, if they are allowed to <em>(based on your configuration below)</em>.</p>'."\n";
135
  echo (c_ws_plugin__s2member_utils_conds::bp_is_installed()) ? '<p><em><strong>BuddyPress:</strong> BuddyPress will use its own Registration Form, powered by your theme.<br />(BuddyPress can handle both Membership and Blog creation in its integration)<br />(<a href="'.esc_attr(c_ws_plugin__s2member_utils_urls::bp_register_url()).'" target="_blank" rel="external" onclick="alert(\'s2Member will now open your BuddyPress Registration Form.\\n* However, you will probably be redirected away from this BuddyPress Registration Form ( '.c_ws_plugin__s2member_utils_strings::esc_js_sq(c_ws_plugin__s2member_utils_urls::bp_register_url()).' ), because you\\\'re ALREADY logged-in. Please log out before testing BuddyPress registration.\');">'.esc_html(c_ws_plugin__s2member_utils_urls::bp_register_url()).'</a>)</em></p>'."\n" : '';
136
  do_action("ws_plugin__s2member_during_mms_ops_page_during_left_sections_during_mms_registration", get_defined_vars());
137
 
303
  }
304
  else // Otherwise, we can display a simple notation; leading into Multisite Networking.
305
  {
306
+ echo '<p style="margin-top:0;"><span class="ws-menu-page-hilite">Your WordPress installation does not have Multisite Networking enabled.<br />Which is perfectly OK :-) Multisite Networking is 100% completely optional.</span></p>'."\n";
307
+ echo '<img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/large-icon.png" title="s2Member (a Membership management system for WordPress)" alt="" style="float:right; margin:0 0 0 25px; border:0;" />'."\n";
308
 
309
  if(file_exists($ws_plugin__s2member_temp = dirname(dirname(dirname(__FILE__)))."/readme-ms.txt"))
310
  {
includes/menu-pages/paypal-buttons.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Menu page for the s2Member plugin (PayPal® Button Generator page).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
20
  if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
21
  {
22
  /**
23
- * Menu page for the s2Member plugin (PayPal® Button Generator page).
24
  *
25
  * @package s2Member\Menu_Pages
26
  * @since 110531
@@ -32,7 +32,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
32
  echo '<div class="wrap ws-menu-page">' . "\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>' . "\n";
35
- echo '<h2>s2Member® / PayPal® Buttons</h2>' . "\n";
36
 
37
  echo '<table class="ws-menu-page-table">' . "\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">' . "\n";
@@ -48,11 +48,11 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
48
  if (($ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_levelN_buttons = "ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_level" . $n . "_buttons"))
49
  do_action ($ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_levelN_buttons, get_defined_vars ());
50
 
51
- echo '<div class="ws-menu-page-group" title="PayPal® Buttons For Level #' . $n . ' Access">' . "\n";
52
 
53
  echo '<div class="ws-menu-page-section ws-plugin--s2member-level' . $n . '-buttons-section">' . "\n";
54
  echo '<h3>Button Code Generator For Level #' . $n . ' Access</h3>' . "\n";
55
- echo '<p>Very simple. All you do is customize the form fields provided, for each Membership Level that you plan to offer. Then press (Generate Button Code). These special PayPal® Buttons are customized to work with s2Member seamlessly. Member accounts will be activated instantly, in an automated fashion. When you, or a Member, cancels their Membership, or fails to make payments on time, s2Member will automatically terminate their Membership privileges. s2Member makes extensive use of the PayPal® IPN service. s2Member receives updates from PayPal® behind-the-scene.</p>' . "\n";
56
  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 Membership Options Page. 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";
57
 
58
  if (($ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_levelN_buttons = "ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_level" . $n . "_buttons"))
@@ -73,7 +73,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
73
  echo '<form onsubmit="return false;">' . "\n";
74
  echo '<p id="ws-plugin--s2member-level' . $n . '-trial-line">I\'ll offer the first <input type="text" autocomplete="off" id="ws-plugin--s2member-level' . $n . '-trial-period" value="0" size="6" /> <select id="ws-plugin--s2member-level' . $n . '-trial-term">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-membership-trial-terms.php"))) . '</select> @ $<input type="text" autocomplete="off" id="ws-plugin--s2member-level' . $n . '-trial-amount" value="0.00" size="4" /></p>' . "\n";
75
  echo '<p><span id="ws-plugin--s2member-level' . $n . '-trial-then">Then, </span>I want to charge: $<input type="text" autocomplete="off" id="ws-plugin--s2member-level' . $n . '-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-level' . $n . '-term">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-membership-regular-terms.php"))) . '</select></p>' . "\n";
76
- 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;" tabindex="-1">[?]</a>: <input type="text" autocomplete="off" id="ws-plugin--s2member-level' . $n . '-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-level' . $n . '-currency">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-currencies.php"))) . '</select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalButtonGenerate(\'level' . $n . '\');" class="button-primary" /></p>' . "\n";
77
  echo '<p>Description: <input type="text" autocomplete="off" id="ws-plugin--s2member-level' . $n . '-desc" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_label"]) . ' / description and pricing details here." size="73" /></p>' . "\n";
78
  echo '<p' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '>Custom Capabilities (comma-delimited) <a href="#" onclick="alert(\'Optional. This is VERY advanced.\\nSee: s2Member -› API Scripting -› Custom Capabilities.\\n\\n*ADVANCED TIP: You can specifiy a list of Custom Capabilities that will be (Added) with this purchase. Or, you could tell s2Member to (Remove All) Custom Capabilities that may or may not already exist for a particular Member, and (Add) only the new ones that you specify. To do this, just start your list of Custom Capabilities with `-all`.\\n\\nSo instead of just (Adding) Custom Capabilities:\\nmusic,videos,archives,gifts\\n\\nYou could (Remove All) that may already exist, and then (Add) new ones:\\n-all,calendar,forums,tools\\n\\nOr to just (Remove All) and (Add) nothing:\\n-all\'); return false;" tabindex="-1">[?]</a> <input type="text" maxlength="125" autocomplete="off" id="ws-plugin--s2member-level' . $n . '-ccaps" size="40" /></p>' . "\n";
79
  echo '</form>' . "\n";
@@ -88,7 +88,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
88
  if (($ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_levelN_buttons_before_shortcode = "ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_level" . $n . "_buttons_before_shortcode"))
89
  do_action ($ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_levelN_buttons_before_shortcode, get_defined_vars ());
90
 
91
- echo '<strong>WordPress® Shortcode:</strong> (recommended for both the WordPress® Visual &amp; HTML Editors)<br />' . "\n";
92
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/shortcodes/paypal-checkout-button-shortcode.php")));
93
  $ws_plugin__s2member_temp_s = preg_replace ("/%%level%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($n)), $ws_plugin__s2member_temp_s);
94
  $ws_plugin__s2member_temp_s = preg_replace ("/%%level_label%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_label"])), $ws_plugin__s2member_temp_s);
@@ -96,7 +96,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
96
  echo '<input type="text" autocomplete="off" id="ws-plugin--s2member-level' . $n . '-shortcode" value="' . format_to_edit ($ws_plugin__s2member_temp_s) . '" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;" />' . "\n";
97
 
98
  echo '<div' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '><br />' . "\n";
99
- echo '<strong>Resulting PayPal® Button Code:</strong> (ultimately, your Shortcode will produce this snippet)<br />' . "\n";
100
  echo '<textarea id="ws-plugin--s2member-level' . $n . '-button" rows="8" wrap="off" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;">';
101
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/paypal-checkout-button.php")));
102
  $ws_plugin__s2member_temp_s = preg_replace ("/%%endpoint%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")), $ws_plugin__s2member_temp_s);
@@ -133,15 +133,15 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
133
  {
134
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_modification_buttons", get_defined_vars ());
135
 
136
- echo '<div class="ws-menu-page-group" title="PayPal® Subscr Modification Buttons">' . "\n";
137
 
138
  echo '<div class="ws-menu-page-section ws-plugin--s2member-modification-buttons-section">' . "\n";
139
  echo '<h3>Button Code Generator For Subscription Modifications</h3>' . "\n";
140
- echo '<p>If you\'d like to give your Members <em>(and/or your Free Subscribers)</em> 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";
141
- echo '<p><em><strong>*Important Note*</strong> Modification Buttons should be displayed to existing Users/Members, and they should be logged-in, BEFORE clicking this Button. Otherwise, post-processing of their transaction will fail to recognize the Customer\'s existing account within WordPress®. Please display this Button only to Users/Members that are already logged into their account (perhaps in your Login Welcome Page for s2Member), or in another location where you can be absolutely sure that a User/Member is logged in. s2Member\'s Simple Conditionals could also be used to ensure a User/Member is logged in, by wrapping your Shortcode within a Conditional test. For further details, please see: <code>s2Member -› API Scripting -› Simple Conditionals</code>.</em></p>' . "\n";
142
- 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 to the registration screen.</em></p>' . "\n";
143
- 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 <em>(the ones who wish to upgrade)</em> 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 <em>(and anything already associated with that Username)</em>, rather than being forced to re-register after checkout.</em></p>' . "\n";
144
- 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";
145
  echo '<p><em><strong>*Integrating Conditionals*</strong> Since each Modification Button is configured for a specific Level, you may want to create multiple Modification Buttons, one for each combination you intend to make available. s2Member\'s API Conditionals can help you display the proper Button to each Customer, based on the status of their existing account. For further details, see: <code>s2Member -› API Scripting</code>.</em></p>' . "\n";
146
  echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '<p><em><strong>*Independent Custom Capabilities*</strong> If you just want to sell an existing Member new Custom Capabilities, without affecting their paid Subscription in any way, please see the next Button Generator: <code>Capability (Buy Now) Buttons</code>. Independent Capability Buttons facilitate Buy Now functionality, specifically for Custom Capabilities, without affecting the Customer\'s primary Subscription and Membership Level Access.</em></p>' . "\n" : '';
147
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_modification_buttons", get_defined_vars ());
@@ -176,7 +176,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
176
 
177
  echo '<p id="ws-plugin--s2member-modification-trial-line">I\'ll offer the first <input type="text" autocomplete="off" id="ws-plugin--s2member-modification-trial-period" value="0" size="6" /> <select id="ws-plugin--s2member-modification-trial-term">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-membership-trial-terms.php"))) . '</select> @ $<input type="text" autocomplete="off" id="ws-plugin--s2member-modification-trial-amount" value="0.00" size="4" /></p>' . "\n";
178
  echo '<p><span id="ws-plugin--s2member-modification-trial-then">Then, </span>I want to charge: $<input type="text" autocomplete="off" id="ws-plugin--s2member-modification-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-modification-term">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-membership-regular-terms.php"))) . '</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;" tabindex="-1">[?]</a>: <input type="text" autocomplete="off" id="ws-plugin--s2member-modification-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-modification-currency">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-currencies.php"))) . '</select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalButtonGenerate(\'modification\');" class="button-primary" /></p>' . "\n";
180
  echo '<p>Description: <input type="text" autocomplete="off" id="ws-plugin--s2member-modification-desc" value="Description and pricing details here." size="73" /></p>' . "\n";
181
  echo '<p' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '>Custom Capabilities (comma-delimited) <a href="#" onclick="alert(\'Optional. This is VERY advanced.\\nSee: s2Member -› API Scripting -› Custom Capabilities.\\n\\n*ADVANCED TIP: You can specifiy a list of Custom Capabilities that will be (Added) with this purchase. Or, you could tell s2Member to (Remove All) Custom Capabilities that may or may not already exist for a particular Member, and (Add) only the new ones that you specify. To do this, just start your list of Custom Capabilities with `-all`.\\n\\nSo instead of just (Adding) Custom Capabilities:\\nmusic,videos,archives,gifts\\n\\nYou could (Remove All) that may already exist, and then (Add) new ones:\\n-all,calendar,forums,tools\\n\\nOr to just (Remove All) and (Add) nothing:\\n-all\'); return false;" tabindex="-1">[?]</a> <input type="text" maxlength="125" autocomplete="off" id="ws-plugin--s2member-modification-ccaps" size="40" /></p>' . "\n";
182
  echo '</form>' . "\n";
@@ -188,7 +188,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
188
  echo '<td colspan="2">' . "\n";
189
  echo '<form onsubmit="return false;">' . "\n";
190
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_modification_buttons_before_shortcode", get_defined_vars ());
191
- echo '<strong>WordPress® Shortcode:</strong> (recommended for both the WordPress® Visual &amp; HTML Editors)<br />' . "\n";
192
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/shortcodes/paypal-checkout-button-shortcode.php")));
193
  $ws_plugin__s2member_temp_s = preg_replace ("/%%level%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ("1")), $ws_plugin__s2member_temp_s);
194
  $ws_plugin__s2member_temp_s = preg_replace ("/%%level_label%% /", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_label"])), $ws_plugin__s2member_temp_s);
@@ -197,7 +197,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
197
  echo '<input type="text" autocomplete="off" id="ws-plugin--s2member-modification-shortcode" value="' . format_to_edit ($ws_plugin__s2member_temp_s) . '" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;" />' . "\n";
198
 
199
  echo '<div' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '><br />' . "\n";
200
- echo '<strong>Resulting PayPal® Button Code:</strong> (ultimately, your Shortcode will produce this snippet)<br />' . "\n";
201
  echo '<textarea id="ws-plugin--s2member-modification-button" rows="8" wrap="off" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;">';
202
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/paypal-checkout-button.php")));
203
  $ws_plugin__s2member_temp_s = preg_replace ('/name\="modify" value\="(.*?)"/', 'name="modify" value="1"', $ws_plugin__s2member_temp_s);
@@ -233,16 +233,16 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
233
  {
234
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_ccap_buttons", get_defined_vars ());
235
 
236
- echo '<div class="ws-menu-page-group" title="PayPal® Capability (Buy Now) Buttons">' . "\n";
237
 
238
  echo '<div class="ws-menu-page-section ws-plugin--s2member-ccap-buttons-section">' . "\n";
239
  echo '<h3>Button Code Generator For Independent Custom Capabilities</h3>' . "\n";
240
  echo '<p>This is VERY advanced. For further details, please check your Dashboard: <code>s2Member -› API Scripting -› Custom Capabiities</code>.</p>' . "\n";
241
  echo '<p>With s2Member, you can sell one or more Custom Capabilities using Buy Now functionality, to "existing" Users/Members, regardless of which Membership Level they have on your site <em>(i.e. you could even sell Independent Custom Capabilities to Users at Membership Level #0, normally referred to as Free Subscribers, if you like)</em>. So this is quite flexible. Independent Custom Capabilities do NOT rely on any specific Membership Level. That\'s why s2Member refers to these as `Independent` Custom Capabilities, because you can sell Capabilities this way, through Buy Now functionality, and the Customer\'s Membership Level Access, along with any existing paid Subscription they may already have with you, will remain completely unaffected. That being said, if you intend to charge a recurring fee for Custom Capabilities, please use a <code>Subscr. Modification Button</code> instead; because Independent Custom Capabilities can only be sold through Buy Now functionality.</p>' . "\n";
242
  echo '<p>Independent Custom Capabilities are added to a Customer\'s account immediately after checkout, and the Customer will have the Custom Capabilities for as long as their Membership lasts, based on their primary Subscription with your site, and/or forever, if they have a Lifetime account with you. In other words, Independent Custom Capabilities will exist on the Customer\'s account forever, or until an EOT <em>(End Of Term)</em> occurs on their primary Subscription with you; in which case s2Member would demote or delete the Customer\'s account <em>(based on your EOT configuration)</em>, and all Custom Capabilities are removed as well.</p>' . "\n";
243
- echo '<p>Very simple. All you do is customize the form fields provided, for each set of Custom Capabilities that you plan to sell. Then press (Generate Button Code). These special PayPal® Buttons are customized to work with s2Member seamlessly. The Customer will be granted additional access to one or more Custom Capabilities that you specify; while the Customer\'s Membership Level Access and any existing paid Subscription they may already have with you, will remain completely unaffected.</p>' . "\n";
244
- echo '<p><em><strong>*Important Note*</strong> Independent Custom Capability Buttons should ONLY be displayed to existing Users/Members, and they MUST be logged-in, BEFORE clicking this Button. Otherwise, post-processing of their transaction will fail to recognize the Customer\'s existing account within WordPress®. Please display this Button only to Users/Members that are already logged into their account (perhaps in your Login Welcome Page for s2Member), or in another location where you can be absolutely sure that a User/Member is logged in. s2Member\'s Simple Conditionals could also be used to ensure a User/Member is logged in, by wrapping your Shortcode within a Conditional test. For further details, please see: <code>s2Member -› API Scripting -› Simple Conditionals</code>.</em></p>' . "\n";
245
- 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. 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";
246
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_ccap_buttons", get_defined_vars ());
247
 
248
  echo '<table class="form-table">' . "\n";
@@ -259,7 +259,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
259
  echo '<td>' . "\n";
260
  echo '<form onsubmit="return false;">' . "\n";
261
  echo '<p>I want to charge: $<input type="text" autocomplete="off" id="ws-plugin--s2member-ccap-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-ccap-term">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-membership-ccap-terms.php"))) . '</select></p>' . "\n";
262
- 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;" tabindex="-1">[?]</a>: <input type="text" autocomplete="off" id="ws-plugin--s2member-ccap-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-ccap-currency">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-currencies.php"))) . '</select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalCcapButtonGenerate();" class="button-primary" /></p>' . "\n";
263
  echo '<p>Description: <input type="text" autocomplete="off" id="ws-plugin--s2member-ccap-desc" value="Description and pricing details here." size="73" /></p>' . "\n";
264
  echo '<p>Custom Capabilities (comma-delimited) <a href="#" onclick="alert(\'Optional. This is VERY advanced.\\nSee: s2Member -› API Scripting -› Custom Capabilities.\\n\\n*ADVANCED TIP: You can specifiy a list of Custom Capabilities that will be (Added) with this purchase. Or, you could tell s2Member to (Remove All) Custom Capabilities that may or may not already exist for a particular Member, and (Add) only the new ones that you specify. To do this, just start your list of Custom Capabilities with `-all`.\\n\\nSo instead of just (Adding) Custom Capabilities:\\nmusic,videos,archives,gifts\\n\\nYou could (Remove All) that may already exist, and then (Add) new ones:\\n-all,calendar,forums,tools\'); return false;" tabindex="-1">[?]</a> <input type="text" maxlength="125" autocomplete="off" id="ws-plugin--s2member-ccap-ccaps" size="40" /></p>' . "\n";
265
  echo '</form>' . "\n";
@@ -271,13 +271,13 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
271
  echo '<td colspan="2">' . "\n";
272
  echo '<form onsubmit="return false;">' . "\n";
273
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_ccap_buttons_before_shortcode", get_defined_vars ());
274
- echo '<strong>WordPress® Shortcode:</strong> (recommended for both the WordPress® Visual &amp; HTML Editors)<br />' . "\n";
275
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/shortcodes/paypal-ccaps-checkout-button-shortcode.php")));
276
  $ws_plugin__s2member_temp_s = preg_replace ("/%%custom%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($_SERVER["HTTP_HOST"])), $ws_plugin__s2member_temp_s);
277
  echo '<input type="text" autocomplete="off" id="ws-plugin--s2member-ccap-shortcode" value="' . format_to_edit ($ws_plugin__s2member_temp_s) . '" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;" />' . "\n";
278
 
279
  echo '<div' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '><br />' . "\n";
280
- echo '<strong>Resulting PayPal® Button Code:</strong> (ultimately, your Shortcode will produce this snippet)<br />' . "\n";
281
  echo '<textarea id="ws-plugin--s2member-ccap-button" rows="8" wrap="off" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;">';
282
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/paypal-ccaps-checkout-button.php")));
283
  $ws_plugin__s2member_temp_s = preg_replace ("/%%endpoint%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")), $ws_plugin__s2member_temp_s);
@@ -310,14 +310,14 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
310
  {
311
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_cancellation_buttons", get_defined_vars ());
312
 
313
- echo '<div class="ws-menu-page-group" title="PayPal® Subscr Cancellation Buttons">' . "\n";
314
 
315
  echo '<div class="ws-menu-page-section ws-plugin--s2member-cancellation-buttons-section">' . "\n";
316
  echo '<h3>One Button Does It All For Cancellations (copy/paste)</h3>' . "\n";
317
- echo '<p>Since all recurring charges are 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";
318
- 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";
319
  echo '<p><em><strong>*Understanding Cancellations*</strong> It\'s important to realize that a Cancellation is not an EOT (End Of Term). All that happens during a Cancellation event, is that billing is stopped, and it\'s understood that the Customer is going to lose access, at some point in the future. This does NOT mean, that access will be revoked immediately. A separate EOT event will automatically handle a (demotion or deletion) later, at the appropriate time; which could be several days, or even a year after the Cancellation took place.</em></p>' . "\n";
320
- echo '<p><em><strong>*Some Hairy Details*</strong> There might be times whenever you notice that a Member\'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 an EOT (End Of Term) is processed, a refund occurs, a chargeback occurs, or when a cancellation occurs - which would later result in a delayed Auto-EOT by s2Member.</em></p>' . "\n";
321
  echo '<p><em>s2Member will not process an EOT (End Of Term) 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";
322
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_cancellation_buttons", get_defined_vars ());
323
 
@@ -351,12 +351,12 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
351
  echo '<td colspan="2">' . "\n";
352
  echo '<form onsubmit="return false;">' . "\n";
353
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_cancellation_buttons_before_shortcode", get_defined_vars ());
354
- echo '<strong>WordPress® Shortcode:</strong> (recommended for both the WordPress® Visual &amp; HTML Editors)<br />' . "\n";
355
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/shortcodes/paypal-cancellation-button-shortcode.php")));
356
  echo '<input type="text" autocomplete="off" id="ws-plugin--s2member-cancellation-shortcode" value="' . format_to_edit ($ws_plugin__s2member_temp_s) . '" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;" />' . "\n";
357
 
358
  echo '<div' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '><br />' . "\n";
359
- echo '<strong>Resulting PayPal® Button Code:</strong> (ultimately, your Shortcode will produce this snippet)<br />' . "\n";
360
  echo '<textarea id="ws-plugin--s2member-cancellation-button" rows="8" wrap="off" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;">';
361
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/paypal-cancellation-button.php")));
362
  $ws_plugin__s2member_temp_s = preg_replace ("/%%endpoint%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")), $ws_plugin__s2member_temp_s);
@@ -385,7 +385,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
385
  {
386
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_reg_links", get_defined_vars ());
387
 
388
- echo '<div class="ws-menu-page-group" title="PayPal® Member Registration Access Links">' . "\n";
389
 
390
  echo '<div class="ws-menu-page-section ws-plugin--s2member-reg-links-section">' . "\n";
391
  echo '<h3>Registration Access Link Generator (for Customer Service)</h3>' . "\n";
@@ -402,7 +402,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
402
  for ($n = 1; $n <= $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]; $n++)
403
  echo '<option value="' . $n . '">s2Member Level #' . $n . '</option>' . "\n";
404
  echo '</select></p>' . "\n";
405
- echo '<p>Paid Subscr. ID: <input type="text" autocomplete="off" id="ws-plugin--s2member-reg-link-subscr-id" value="" size="50" /> <a href="#" onclick="alert(\'The Customer\\\'s Paid Subscr. ID (aka: Recurring Profile ID, Transaction ID) must be unique. This value can be obtained from inside your PayPal® account under the History tab. Each paying Customer MUST be associated with a unique Paid Subscr. ID. If the Customer is NOT associated with a Paid Subscr. ID, you will need to generate a unique value for this field on your own. But keep in mind, s2Member will be unable to maintain future communication with the PayPal® IPN (i.e. Notification) service if this value does not reflect a real Paid Subscr. ID that exists in your PayPal® History log.\'); return false;" tabindex="-1">[?]</a></p>' . "\n";
406
  echo '<p>Custom String Value: <input type="text" autocomplete="off" id="ws-plugin--s2member-reg-link-custom" value="' . esc_attr ($_SERVER["HTTP_HOST"]) . '" size="30" /> <a href="#" onclick="alert(\'A Paid Subscription is always associated with a Custom String that is passed through the custom=\\\'\\\'' . c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"]), 3) . '\\\'\\\' attribute of your Shortcode. This Custom Value, MUST always start with your domain name. However, you can also pipe delimit additional values after your domain, if you need to.\\n\\nFor example:\n' . c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"]), 3) . '|cv1|cv2|cv3\'); return false;" tabindex="-1">[?]</a> <input type="button" value="Generate Access Link" onclick="ws_plugin__s2member_paypalRegLinkGenerate();" class="button-primary" /> <img id="ws-plugin--s2member-reg-link-loading" src="' . esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]) . '/images/ajax-loader.gif" alt="" style="display:none;" /></p>' . "\n";
407
  echo '<p' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '>Custom Capabilities (comma-delimited) <a href="#" onclick="alert(\'Optional. This is VERY advanced.\\nSee: s2Member -› API Scripting -› Custom Capabilities.\'); return false;" tabindex="-1">[?]</a> <input type="text" maxlength="125" autocomplete="off" id="ws-plugin--s2member-reg-link-ccaps" size="40" onkeyup="if(this.value.match(/[^a-z_0-9,]/)) this.value = jQuery.trim (jQuery.trim (this.value).replace (/[ \-]/g, \'_\').replace (/[^a-z_0-9,]/gi, \'\').toLowerCase ());" /></p>' . "\n";
408
  echo '<p>Fixed Term Length (for Buy Now transactions): <input type="text" autocomplete="off" id="ws-plugin--s2member-reg-link-fixed-term" value="" size="10" /> <a href="#" onclick="alert(\'If the Customer purchased Membership through a Buy Now transaction (i.e. there is no Initial/Trial Period and no recurring charges for ongoing access), you may configure a Fixed Term Length in this field. This way the Customer\\\'s Membership Access is automatically revoked by s2Member at the appropriate time. This will be a numeric value, followed by a space, then a single letter.\\n\\nHere are some examples:\\n\\n1 D (this means 1 Day)\\n1 W (this means 1 Week)\\n1 M (this means 1 Month)\\n1 Y (this means 1 Year)\\n1 L (this means 1 Lifetime)\'); return false;">[?]</a></p>' . "\n";
@@ -424,15 +424,15 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
424
  {
425
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_sp_buttons", get_defined_vars ());
426
 
427
- echo '<div class="ws-menu-page-group" title="PayPal® Specific Post/Page (Buy Now) Buttons">' . "\n";
428
 
429
  echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-buttons-section">' . "\n";
430
  echo '<h3>Button Code Generator For Specific Post/Page Buttons</h3>' . "\n";
431
- 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";
432
- 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";
433
- 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 -› Restriction Options -› Specific Post/Page Access</code>. Once you\'ve configured your Specific Post/Page Restrictions, those Posts/Pages will be available in the menus below.</p>' . "\n";
434
- 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";
435
- 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. 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";
436
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_sp_buttons", get_defined_vars ());
437
 
438
  echo '<table class="form-table">' . "\n";
@@ -469,7 +469,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
469
 
470
  echo '<p>I want to charge: $<input type="text" autocomplete="off" id="ws-plugin--s2member-sp-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-sp-hours">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-sp-hours.php"))) . '</select></p>' . "\n";
471
  echo '<p>Description: <input type="text" autocomplete="off" id="ws-plugin--s2member-sp-desc" value="Description and pricing details here." size="68" /></p>' . "\n";
472
- 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;" tabindex="-1">[?]</a>: <input type="text" autocomplete="off" id="ws-plugin--s2member-sp-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-sp-currency">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-currencies.php"))) . '</select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalSpButtonGenerate();" class="button-primary" /></p>' . "\n";
473
  echo '</form>' . "\n";
474
  echo '</td>' . "\n";
475
 
@@ -479,13 +479,13 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
479
  echo '<td colspan="2">' . "\n";
480
  echo '<form onsubmit="return false;">' . "\n";
481
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_sp_buttons_before_shortcode", get_defined_vars ());
482
- echo '<strong>WordPress® Shortcode:</strong> (recommended for both the WordPress® Visual &amp; HTML Editors)<br />' . "\n";
483
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/shortcodes/paypal-sp-checkout-button-shortcode.php")));
484
  $ws_plugin__s2member_temp_s = preg_replace ("/%%custom%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($_SERVER["HTTP_HOST"])), $ws_plugin__s2member_temp_s);
485
  echo '<input type="text" autocomplete="off" id="ws-plugin--s2member-sp-shortcode" value="' . format_to_edit ($ws_plugin__s2member_temp_s) . '" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;" />' . "\n";
486
 
487
  echo '<div' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '><br />' . "\n";
488
- echo '<strong>Resulting PayPal® Button Code:</strong> (ultimately, your Shortcode will produce this snippet)<br />' . "\n";
489
  echo '<textarea id="ws-plugin--s2member-sp-button" rows="8" wrap="off" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;">';
490
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/paypal-sp-checkout-button.php")));
491
  $ws_plugin__s2member_temp_s = preg_replace ("/%%endpoint%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")), $ws_plugin__s2member_temp_s);
@@ -518,7 +518,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
518
  {
519
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_sp_links", get_defined_vars ());
520
 
521
- echo '<div class="ws-menu-page-group" title="PayPal® Specific Post/Page Access Links">' . "\n";
522
 
523
  echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-links-section">' . "\n";
524
  echo '<h3>Specific Post/Page Link Generator (for Customer Service)</h3>' . "\n";
@@ -573,7 +573,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
573
 
574
  echo '<div class="ws-menu-page-section ws-plugin--s2member-shortcode-attrs-section">' . "\n";
575
  echo '<h3>Shortcode Attributes (Explained In Full Detail)</h3>' . "\n";
576
- echo '<p>When you generate a Button Code, s2Member will make a <a href="http://codex.wordpress.org/Shortcode_API#Overview" target="_blank" rel="external">Shortcode</a> available to you. Like most Shortcodes for WordPress®, s2Member reads Attributes in your Shortcode. These Attributes will be pre-configured by one of s2Member\'s Button Generators automatically; so there really is nothing more you need to do. However, many site owners like to know exactly how these Shortcode Attributes work. Below, is a brief overview of each possible Shortcode Attribute.</p>' . "\n";
577
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_shortcode_attrs", get_defined_vars ());
578
 
579
  echo '<table class="form-table" style="margin-top:0;">' . "\n";
@@ -590,20 +590,20 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
590
  echo '<li><code>dg="0"</code> The Digital Goods directive. s2Member will eventually be integrated with <a href="http://www.s2member.com/paypal-express-co-digitals" target="_blank" rel="external">Digital Goods</a> for inline Express Checkout. But for now, this should always be <code>0</code>.</li>' . "\n";
591
  echo '<li><code>exp="72"</code> Access Expires (in hours). Only valid when <code>sp="1"</code> for Specific Post/Page Access.</li>' . "\n";
592
  echo '<li><code>ids="14"</code> A Post/Page ID#, or a comma-delimited list of IDs. Only valid when <code>sp="1"</code> for Specific Post/Page Access.</li>' . "\n";
593
- echo '<li><code>image="default"</code> Button Image Location. Possible values: <code>default</code> = use the default PayPal® Button, <code>http://...</code> = location of your custom Image.</li>' . "\n";
594
- echo '<li><code>lang=""</code> Optional 5 character Button Language Code <em>(ake: Locale Code — ex: <code>en_US</code>)</em>. This controls the interface language of the PayPal® Button itself. If unspecified, the language defaults to English (i.e. <code>en_US</code>; or to the value set by an optional MO translation file; which translates s2Member® overall). See <a href="https://cms.paypal.com/mx/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ECButtonIntegration#id089QD0O0TX4__id08AH904I0YK" target="_blank" rel="external">this list of possible Locale Codes</a>.</li>' . "\n";
595
- echo '<li><code>lc=""</code> Optional 2 character Country/Locale Code <em>(i.e. Country Code — ex: <code>US</code>)</em>. This controls the interface language used at PayPal® during checkout. If unspecified, the language is determined by PayPal® when possible, defaulting to <code>US</code> <em>english</em> when not possible. See <a href="https://cms.paypal.com/mx/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ECButtonIntegration#id089QD0O0TX4__id08AH904I0YK" target="_blank" rel="external">this list of possible Country Codes</a>. Not valid when <code>cancel="1"</code>.</li>' . "\n";
596
  echo '<li><code>level="1"</code> Membership Level [1-4] <em>(or, up to the number of configured Levels)</em>. Only valid for Buttons providing paid Membership Level Access.' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' Or, with Independent Custom Capabilities this MUST be set to <code>level="*"</code>, and <code>ccaps=""</code> must NOT be empty <em>(i.e. <code>level="*" ccaps="music,videos"</code>)</em>.') . '</li>' . "\n";
597
  echo '<li><code>modify="0"</code> Modification directive. Only valid w/ Membership Level Access. Possible values: <code>0</code> = allows Customers to only create a new Subscription, <code>1</code> = allows Customers to modify their current Subscription or sign up for a new one, <code>2</code> = allows Customers to only modify their current Subscription.</li>' . "\n";
598
  echo '<li><code>ns="1"</code> The <em>no_shipping</em> directive. Possible values: <code>0</code> = prompt for an address, but do not require one, <code>1</code> = do not prompt for a shipping address, <code>2</code> = prompt for an address, and require one. Not valid when <code>cancel="1"</code>.</li>' . "\n";
599
- echo '<li><code>output="button"</code> Output Type. Possible values: <code>button</code> = PayPal® Button w/hidden inputs, <code>anchor</code> = PayPal® Button ( &lt;a&gt; anchor tag ) URL w/ ?query string, <code>url</code> = raw URL w/ ?query string.</li>' . "\n";
600
- echo '<li><code>ps="paypal"</code> PayPal® checkout Page Style. Not valid when <code>cancel="1"</code>.</li>' . "\n";
601
  echo '<li><code>ra="0.01"</code> Regular, Buy Now, and/or Recurring Amount. Must be &gt;= <code>0.01</code>. Not valid when <code>cancel="1"</code>.</li>' . "\n";
602
  echo '<li><code>rp="1"</code> Regular Period. Only valid w/ Membership Level Access' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' and/or Independent Custom Capabilities') . '. Must be &gt;= <code>1</code> (ex: <code>1</code> Week, <code>2</code> Months, <code>1</code> Month, <code>3</code> Days).</li>' . "\n";
603
  echo '<li><code>rt="M"</code> Regular Term. Only valid w/ Membership Level Access' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' and/or Independent Custom Capabilities') . '. Possible values: <code>D</code> = Days, <code>W</code> = Weeks, <code>M</code> = Months, <code>Y</code> = Years, <code>L</code> = Lifetime.</li>' . "\n";
604
  echo '<li><code>rr="1"</code> Recurring directive. Only valid w/ Membership Level Access' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' and/or Independent Custom Capabilities') . '. Possible values: <code>0</code> = non-recurring "Subscription" with possible Trial Period for free, or at a different Trial Amount; <code>1</code> = recurring "Subscription" with possible Trial Period for free, or at a different Trial Amount; <code>BN</code> = non-recurring "Buy Now" functionality, no Trial Period possible.</li>' . "\n";
605
- echo '<li><code>rrt=""</code> Recurring Times <em>(i.e. a fixed number of installments)</em>. Only valid w/ Membership Level Access. When unspecified, any recurring charges will remain ongoing until cancelled, or until payments start failing. If this is set to <code>1 or higher</code> the regular recurring charges will only continue for X billing cycles, depending on what you specify. This is only valid when <code>rr="1"</code> for recurring "Subscriptions". Please note that a fixed number of installments, also means a fixed period of access. If a Customer\'s billing is monthly, and you set <code>rrt="3"</code>, billing will continue for only 3 monthly installments. After that, billing would stop, and their access to the site would be revoked as well <em>(based on your EOT Behavior setting under: s2Member -› PayPal® Options)</em>.</li>' . "\n";
606
- echo '<li><code>rra="1"</code> Reattempt failed payments? Possible values: <code>0</code> = do NOT reattempt billing when/if a recurring payment fails; <code>1</code> = yes, DO reattempt billing when/if a recurring payment fails. With PayPal® Standard integration, PayPal® will retry a maximum of 2 times when you set <code>rra="1"</code>; after that, a Subscription would be terminated due to Max Failed Payments having been reached. PayPal® Standard integration does NOT make it possible to configure Max Failed Payments, it simply defaults to a value of <code>2</code> whenever <code>rra="1"</code>, indicating that you DO want to retry failed payments.</li>' . "\n";
607
  echo '<li><code>sp="0"</code> Specific Post/Page Button. Possible values: <code>0</code> = this is NOT a Specific Post/Page Access Button, <code>1</code> = this IS a Specific Post/Page Access Button.</li>' . "\n";
608
  echo '<li><code>ta="0.00"</code> Trial Amount. Only valid w/ Membership Level Access. Must be <code>0</code> when <code>rt="L"</code> or when <code>rr="BN"</code>.</li>' . "\n";
609
  echo '<li><code>tp="0"</code> Trial Period. Only valid w/ Membership Level Access. Must be <code>0</code> when <code>rt="L"</code> or when <code>rr="BN"</code>.</li>' . "\n";
1
  <?php
2
  /**
3
+ * Menu page for the s2Member plugin (PayPal Button Generator page).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if (!class_exists ("c_ws_plugin__s2member_menu_page_paypal_buttons"))
21
  {
22
  /**
23
+ * Menu page for the s2Member plugin (PayPal Button Generator page).
24
  *
25
  * @package s2Member\Menu_Pages
26
  * @since 110531
32
  echo '<div class="wrap ws-menu-page">' . "\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>' . "\n";
35
+ echo '<h2>s2Member / PayPal Buttons</h2>' . "\n";
36
 
37
  echo '<table class="ws-menu-page-table">' . "\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">' . "\n";
48
  if (($ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_levelN_buttons = "ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_level" . $n . "_buttons"))
49
  do_action ($ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_levelN_buttons, get_defined_vars ());
50
 
51
+ echo '<div class="ws-menu-page-group" title="PayPal Buttons For Level #' . $n . ' Access">' . "\n";
52
 
53
  echo '<div class="ws-menu-page-section ws-plugin--s2member-level' . $n . '-buttons-section">' . "\n";
54
  echo '<h3>Button Code Generator For Level #' . $n . ' Access</h3>' . "\n";
55
+ echo '<p>Very simple. All you do is customize the form fields provided, for each Membership Level that you plan to offer. Then press (Generate Button Code). These special PayPal Buttons are customized to work with s2Member seamlessly. Member accounts will be activated instantly, in an automated fashion. When you, or a Member, cancels their Membership, or fails to make payments on time, s2Member will automatically terminate their Membership privileges. s2Member makes extensive use of the PayPal IPN service. s2Member receives updates from PayPal behind-the-scene.</p>' . "\n";
56
  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 Membership Options Page. 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";
57
 
58
  if (($ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_levelN_buttons = "ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_level" . $n . "_buttons"))
73
  echo '<form onsubmit="return false;">' . "\n";
74
  echo '<p id="ws-plugin--s2member-level' . $n . '-trial-line">I\'ll offer the first <input type="text" autocomplete="off" id="ws-plugin--s2member-level' . $n . '-trial-period" value="0" size="6" /> <select id="ws-plugin--s2member-level' . $n . '-trial-term">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-membership-trial-terms.php"))) . '</select> @ $<input type="text" autocomplete="off" id="ws-plugin--s2member-level' . $n . '-trial-amount" value="0.00" size="4" /></p>' . "\n";
75
  echo '<p><span id="ws-plugin--s2member-level' . $n . '-trial-then">Then, </span>I want to charge: $<input type="text" autocomplete="off" id="ws-plugin--s2member-level' . $n . '-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-level' . $n . '-term">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-membership-regular-terms.php"))) . '</select></p>' . "\n";
76
+ 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;" tabindex="-1">[?]</a>: <input type="text" autocomplete="off" id="ws-plugin--s2member-level' . $n . '-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-level' . $n . '-currency">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-currencies.php"))) . '</select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalButtonGenerate(\'level' . $n . '\');" class="button-primary" /></p>' . "\n";
77
  echo '<p>Description: <input type="text" autocomplete="off" id="ws-plugin--s2member-level' . $n . '-desc" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_label"]) . ' / description and pricing details here." size="73" /></p>' . "\n";
78
  echo '<p' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '>Custom Capabilities (comma-delimited) <a href="#" onclick="alert(\'Optional. This is VERY advanced.\\nSee: s2Member -› API Scripting -› Custom Capabilities.\\n\\n*ADVANCED TIP: You can specifiy a list of Custom Capabilities that will be (Added) with this purchase. Or, you could tell s2Member to (Remove All) Custom Capabilities that may or may not already exist for a particular Member, and (Add) only the new ones that you specify. To do this, just start your list of Custom Capabilities with `-all`.\\n\\nSo instead of just (Adding) Custom Capabilities:\\nmusic,videos,archives,gifts\\n\\nYou could (Remove All) that may already exist, and then (Add) new ones:\\n-all,calendar,forums,tools\\n\\nOr to just (Remove All) and (Add) nothing:\\n-all\'); return false;" tabindex="-1">[?]</a> <input type="text" maxlength="125" autocomplete="off" id="ws-plugin--s2member-level' . $n . '-ccaps" size="40" /></p>' . "\n";
79
  echo '</form>' . "\n";
88
  if (($ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_levelN_buttons_before_shortcode = "ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_level" . $n . "_buttons_before_shortcode"))
89
  do_action ($ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_levelN_buttons_before_shortcode, get_defined_vars ());
90
 
91
+ echo '<strong>WordPress Shortcode:</strong> (recommended for both the WordPress Visual &amp; HTML Editors)<br />' . "\n";
92
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/shortcodes/paypal-checkout-button-shortcode.php")));
93
  $ws_plugin__s2member_temp_s = preg_replace ("/%%level%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($n)), $ws_plugin__s2member_temp_s);
94
  $ws_plugin__s2member_temp_s = preg_replace ("/%%level_label%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $n . "_label"])), $ws_plugin__s2member_temp_s);
96
  echo '<input type="text" autocomplete="off" id="ws-plugin--s2member-level' . $n . '-shortcode" value="' . format_to_edit ($ws_plugin__s2member_temp_s) . '" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;" />' . "\n";
97
 
98
  echo '<div' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '><br />' . "\n";
99
+ echo '<strong>Resulting PayPal Button Code:</strong> (ultimately, your Shortcode will produce this snippet)<br />' . "\n";
100
  echo '<textarea id="ws-plugin--s2member-level' . $n . '-button" rows="8" wrap="off" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;">';
101
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/paypal-checkout-button.php")));
102
  $ws_plugin__s2member_temp_s = preg_replace ("/%%endpoint%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")), $ws_plugin__s2member_temp_s);
133
  {
134
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_modification_buttons", get_defined_vars ());
135
 
136
+ echo '<div class="ws-menu-page-group" title="PayPal Subscr Modification Buttons">' . "\n";
137
 
138
  echo '<div class="ws-menu-page-section ws-plugin--s2member-modification-buttons-section">' . "\n";
139
  echo '<h3>Button Code Generator For Subscription Modifications</h3>' . "\n";
140
+ echo '<p>If you\'d like to give your Members <em>(and/or your Free Subscribers)</em> 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";
141
+ echo '<p><em><strong>*Important Note*</strong> Modification Buttons should be displayed to existing Users/Members, and they should be logged-in, BEFORE clicking this Button. Otherwise, post-processing of their transaction will fail to recognize the Customer\'s existing account within WordPress. Please display this Button only to Users/Members that are already logged into their account (perhaps in your Login Welcome Page for s2Member), or in another location where you can be absolutely sure that a User/Member is logged in. s2Member\'s Simple Conditionals could also be used to ensure a User/Member is logged in, by wrapping your Shortcode within a Conditional test. For further details, please see: <code>s2Member -› API Scripting -› Simple Conditionals</code>.</em></p>' . "\n";
142
+ 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 to the registration screen.</em></p>' . "\n";
143
+ 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 <em>(the ones who wish to upgrade)</em> 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 <em>(and anything already associated with that Username)</em>, rather than being forced to re-register after checkout.</em></p>' . "\n";
144
+ 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";
145
  echo '<p><em><strong>*Integrating Conditionals*</strong> Since each Modification Button is configured for a specific Level, you may want to create multiple Modification Buttons, one for each combination you intend to make available. s2Member\'s API Conditionals can help you display the proper Button to each Customer, based on the status of their existing account. For further details, see: <code>s2Member -› API Scripting</code>.</em></p>' . "\n";
146
  echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '<p><em><strong>*Independent Custom Capabilities*</strong> If you just want to sell an existing Member new Custom Capabilities, without affecting their paid Subscription in any way, please see the next Button Generator: <code>Capability (Buy Now) Buttons</code>. Independent Capability Buttons facilitate Buy Now functionality, specifically for Custom Capabilities, without affecting the Customer\'s primary Subscription and Membership Level Access.</em></p>' . "\n" : '';
147
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_modification_buttons", get_defined_vars ());
176
 
177
  echo '<p id="ws-plugin--s2member-modification-trial-line">I\'ll offer the first <input type="text" autocomplete="off" id="ws-plugin--s2member-modification-trial-period" value="0" size="6" /> <select id="ws-plugin--s2member-modification-trial-term">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-membership-trial-terms.php"))) . '</select> @ $<input type="text" autocomplete="off" id="ws-plugin--s2member-modification-trial-amount" value="0.00" size="4" /></p>' . "\n";
178
  echo '<p><span id="ws-plugin--s2member-modification-trial-then">Then, </span>I want to charge: $<input type="text" autocomplete="off" id="ws-plugin--s2member-modification-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-modification-term">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-membership-regular-terms.php"))) . '</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;" tabindex="-1">[?]</a>: <input type="text" autocomplete="off" id="ws-plugin--s2member-modification-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-modification-currency">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-currencies.php"))) . '</select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalButtonGenerate(\'modification\');" class="button-primary" /></p>' . "\n";
180
  echo '<p>Description: <input type="text" autocomplete="off" id="ws-plugin--s2member-modification-desc" value="Description and pricing details here." size="73" /></p>' . "\n";
181
  echo '<p' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '>Custom Capabilities (comma-delimited) <a href="#" onclick="alert(\'Optional. This is VERY advanced.\\nSee: s2Member -› API Scripting -› Custom Capabilities.\\n\\n*ADVANCED TIP: You can specifiy a list of Custom Capabilities that will be (Added) with this purchase. Or, you could tell s2Member to (Remove All) Custom Capabilities that may or may not already exist for a particular Member, and (Add) only the new ones that you specify. To do this, just start your list of Custom Capabilities with `-all`.\\n\\nSo instead of just (Adding) Custom Capabilities:\\nmusic,videos,archives,gifts\\n\\nYou could (Remove All) that may already exist, and then (Add) new ones:\\n-all,calendar,forums,tools\\n\\nOr to just (Remove All) and (Add) nothing:\\n-all\'); return false;" tabindex="-1">[?]</a> <input type="text" maxlength="125" autocomplete="off" id="ws-plugin--s2member-modification-ccaps" size="40" /></p>' . "\n";
182
  echo '</form>' . "\n";
188
  echo '<td colspan="2">' . "\n";
189
  echo '<form onsubmit="return false;">' . "\n";
190
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_modification_buttons_before_shortcode", get_defined_vars ());
191
+ echo '<strong>WordPress Shortcode:</strong> (recommended for both the WordPress Visual &amp; HTML Editors)<br />' . "\n";
192
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/shortcodes/paypal-checkout-button-shortcode.php")));
193
  $ws_plugin__s2member_temp_s = preg_replace ("/%%level%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ("1")), $ws_plugin__s2member_temp_s);
194
  $ws_plugin__s2member_temp_s = preg_replace ("/%%level_label%% /", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level1_label"])), $ws_plugin__s2member_temp_s);
197
  echo '<input type="text" autocomplete="off" id="ws-plugin--s2member-modification-shortcode" value="' . format_to_edit ($ws_plugin__s2member_temp_s) . '" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;" />' . "\n";
198
 
199
  echo '<div' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '><br />' . "\n";
200
+ echo '<strong>Resulting PayPal Button Code:</strong> (ultimately, your Shortcode will produce this snippet)<br />' . "\n";
201
  echo '<textarea id="ws-plugin--s2member-modification-button" rows="8" wrap="off" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;">';
202
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/paypal-checkout-button.php")));
203
  $ws_plugin__s2member_temp_s = preg_replace ('/name\="modify" value\="(.*?)"/', 'name="modify" value="1"', $ws_plugin__s2member_temp_s);
233
  {
234
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_ccap_buttons", get_defined_vars ());
235
 
236
+ echo '<div class="ws-menu-page-group" title="PayPal Capability (Buy Now) Buttons">' . "\n";
237
 
238
  echo '<div class="ws-menu-page-section ws-plugin--s2member-ccap-buttons-section">' . "\n";
239
  echo '<h3>Button Code Generator For Independent Custom Capabilities</h3>' . "\n";
240
  echo '<p>This is VERY advanced. For further details, please check your Dashboard: <code>s2Member -› API Scripting -› Custom Capabiities</code>.</p>' . "\n";
241
  echo '<p>With s2Member, you can sell one or more Custom Capabilities using Buy Now functionality, to "existing" Users/Members, regardless of which Membership Level they have on your site <em>(i.e. you could even sell Independent Custom Capabilities to Users at Membership Level #0, normally referred to as Free Subscribers, if you like)</em>. So this is quite flexible. Independent Custom Capabilities do NOT rely on any specific Membership Level. That\'s why s2Member refers to these as `Independent` Custom Capabilities, because you can sell Capabilities this way, through Buy Now functionality, and the Customer\'s Membership Level Access, along with any existing paid Subscription they may already have with you, will remain completely unaffected. That being said, if you intend to charge a recurring fee for Custom Capabilities, please use a <code>Subscr. Modification Button</code> instead; because Independent Custom Capabilities can only be sold through Buy Now functionality.</p>' . "\n";
242
  echo '<p>Independent Custom Capabilities are added to a Customer\'s account immediately after checkout, and the Customer will have the Custom Capabilities for as long as their Membership lasts, based on their primary Subscription with your site, and/or forever, if they have a Lifetime account with you. In other words, Independent Custom Capabilities will exist on the Customer\'s account forever, or until an EOT <em>(End Of Term)</em> occurs on their primary Subscription with you; in which case s2Member would demote or delete the Customer\'s account <em>(based on your EOT configuration)</em>, and all Custom Capabilities are removed as well.</p>' . "\n";
243
+ echo '<p>Very simple. All you do is customize the form fields provided, for each set of Custom Capabilities that you plan to sell. Then press (Generate Button Code). These special PayPal Buttons are customized to work with s2Member seamlessly. The Customer will be granted additional access to one or more Custom Capabilities that you specify; while the Customer\'s Membership Level Access and any existing paid Subscription they may already have with you, will remain completely unaffected.</p>' . "\n";
244
+ echo '<p><em><strong>*Important Note*</strong> Independent Custom Capability Buttons should ONLY be displayed to existing Users/Members, and they MUST be logged-in, BEFORE clicking this Button. Otherwise, post-processing of their transaction will fail to recognize the Customer\'s existing account within WordPress. Please display this Button only to Users/Members that are already logged into their account (perhaps in your Login Welcome Page for s2Member), or in another location where you can be absolutely sure that a User/Member is logged in. s2Member\'s Simple Conditionals could also be used to ensure a User/Member is logged in, by wrapping your Shortcode within a Conditional test. For further details, please see: <code>s2Member -› API Scripting -› Simple Conditionals</code>.</em></p>' . "\n";
245
+ 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. 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";
246
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_ccap_buttons", get_defined_vars ());
247
 
248
  echo '<table class="form-table">' . "\n";
259
  echo '<td>' . "\n";
260
  echo '<form onsubmit="return false;">' . "\n";
261
  echo '<p>I want to charge: $<input type="text" autocomplete="off" id="ws-plugin--s2member-ccap-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-ccap-term">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-membership-ccap-terms.php"))) . '</select></p>' . "\n";
262
+ 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;" tabindex="-1">[?]</a>: <input type="text" autocomplete="off" id="ws-plugin--s2member-ccap-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-ccap-currency">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-currencies.php"))) . '</select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalCcapButtonGenerate();" class="button-primary" /></p>' . "\n";
263
  echo '<p>Description: <input type="text" autocomplete="off" id="ws-plugin--s2member-ccap-desc" value="Description and pricing details here." size="73" /></p>' . "\n";
264
  echo '<p>Custom Capabilities (comma-delimited) <a href="#" onclick="alert(\'Optional. This is VERY advanced.\\nSee: s2Member -› API Scripting -› Custom Capabilities.\\n\\n*ADVANCED TIP: You can specifiy a list of Custom Capabilities that will be (Added) with this purchase. Or, you could tell s2Member to (Remove All) Custom Capabilities that may or may not already exist for a particular Member, and (Add) only the new ones that you specify. To do this, just start your list of Custom Capabilities with `-all`.\\n\\nSo instead of just (Adding) Custom Capabilities:\\nmusic,videos,archives,gifts\\n\\nYou could (Remove All) that may already exist, and then (Add) new ones:\\n-all,calendar,forums,tools\'); return false;" tabindex="-1">[?]</a> <input type="text" maxlength="125" autocomplete="off" id="ws-plugin--s2member-ccap-ccaps" size="40" /></p>' . "\n";
265
  echo '</form>' . "\n";
271
  echo '<td colspan="2">' . "\n";
272
  echo '<form onsubmit="return false;">' . "\n";
273
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_ccap_buttons_before_shortcode", get_defined_vars ());
274
+ echo '<strong>WordPress Shortcode:</strong> (recommended for both the WordPress Visual &amp; HTML Editors)<br />' . "\n";
275
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/shortcodes/paypal-ccaps-checkout-button-shortcode.php")));
276
  $ws_plugin__s2member_temp_s = preg_replace ("/%%custom%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($_SERVER["HTTP_HOST"])), $ws_plugin__s2member_temp_s);
277
  echo '<input type="text" autocomplete="off" id="ws-plugin--s2member-ccap-shortcode" value="' . format_to_edit ($ws_plugin__s2member_temp_s) . '" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;" />' . "\n";
278
 
279
  echo '<div' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '><br />' . "\n";
280
+ echo '<strong>Resulting PayPal Button Code:</strong> (ultimately, your Shortcode will produce this snippet)<br />' . "\n";
281
  echo '<textarea id="ws-plugin--s2member-ccap-button" rows="8" wrap="off" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;">';
282
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/paypal-ccaps-checkout-button.php")));
283
  $ws_plugin__s2member_temp_s = preg_replace ("/%%endpoint%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")), $ws_plugin__s2member_temp_s);
310
  {
311
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_cancellation_buttons", get_defined_vars ());
312
 
313
+ echo '<div class="ws-menu-page-group" title="PayPal Subscr Cancellation Buttons">' . "\n";
314
 
315
  echo '<div class="ws-menu-page-section ws-plugin--s2member-cancellation-buttons-section">' . "\n";
316
  echo '<h3>One Button Does It All For Cancellations (copy/paste)</h3>' . "\n";
317
+ echo '<p>Since all recurring charges are 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";
318
+ 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";
319
  echo '<p><em><strong>*Understanding Cancellations*</strong> It\'s important to realize that a Cancellation is not an EOT (End Of Term). All that happens during a Cancellation event, is that billing is stopped, and it\'s understood that the Customer is going to lose access, at some point in the future. This does NOT mean, that access will be revoked immediately. A separate EOT event will automatically handle a (demotion or deletion) later, at the appropriate time; which could be several days, or even a year after the Cancellation took place.</em></p>' . "\n";
320
+ echo '<p><em><strong>*Some Hairy Details*</strong> There might be times whenever you notice that a Member\'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 an EOT (End Of Term) is processed, a refund occurs, a chargeback occurs, or when a cancellation occurs - which would later result in a delayed Auto-EOT by s2Member.</em></p>' . "\n";
321
  echo '<p><em>s2Member will not process an EOT (End Of Term) 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";
322
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_cancellation_buttons", get_defined_vars ());
323
 
351
  echo '<td colspan="2">' . "\n";
352
  echo '<form onsubmit="return false;">' . "\n";
353
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_cancellation_buttons_before_shortcode", get_defined_vars ());
354
+ echo '<strong>WordPress Shortcode:</strong> (recommended for both the WordPress Visual &amp; HTML Editors)<br />' . "\n";
355
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/shortcodes/paypal-cancellation-button-shortcode.php")));
356
  echo '<input type="text" autocomplete="off" id="ws-plugin--s2member-cancellation-shortcode" value="' . format_to_edit ($ws_plugin__s2member_temp_s) . '" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;" />' . "\n";
357
 
358
  echo '<div' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '><br />' . "\n";
359
+ echo '<strong>Resulting PayPal Button Code:</strong> (ultimately, your Shortcode will produce this snippet)<br />' . "\n";
360
  echo '<textarea id="ws-plugin--s2member-cancellation-button" rows="8" wrap="off" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;">';
361
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/paypal-cancellation-button.php")));
362
  $ws_plugin__s2member_temp_s = preg_replace ("/%%endpoint%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")), $ws_plugin__s2member_temp_s);
385
  {
386
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_reg_links", get_defined_vars ());
387
 
388
+ echo '<div class="ws-menu-page-group" title="PayPal Member Registration Access Links">' . "\n";
389
 
390
  echo '<div class="ws-menu-page-section ws-plugin--s2member-reg-links-section">' . "\n";
391
  echo '<h3>Registration Access Link Generator (for Customer Service)</h3>' . "\n";
402
  for ($n = 1; $n <= $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["levels"]; $n++)
403
  echo '<option value="' . $n . '">s2Member Level #' . $n . '</option>' . "\n";
404
  echo '</select></p>' . "\n";
405
+ echo '<p>Paid Subscr. ID: <input type="text" autocomplete="off" id="ws-plugin--s2member-reg-link-subscr-id" value="" size="50" /> <a href="#" onclick="alert(\'The Customer\\\'s Paid Subscr. ID (aka: Recurring Profile ID, Transaction ID) must be unique. This value can be obtained from inside your PayPal account under the History tab. Each paying Customer MUST be associated with a unique Paid Subscr. ID. If the Customer is NOT associated with a Paid Subscr. ID, you will need to generate a unique value for this field on your own. But keep in mind, s2Member will be unable to maintain future communication with the PayPal IPN (i.e. Notification) service if this value does not reflect a real Paid Subscr. ID that exists in your PayPal History log.\'); return false;" tabindex="-1">[?]</a></p>' . "\n";
406
  echo '<p>Custom String Value: <input type="text" autocomplete="off" id="ws-plugin--s2member-reg-link-custom" value="' . esc_attr ($_SERVER["HTTP_HOST"]) . '" size="30" /> <a href="#" onclick="alert(\'A Paid Subscription is always associated with a Custom String that is passed through the custom=\\\'\\\'' . c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"]), 3) . '\\\'\\\' attribute of your Shortcode. This Custom Value, MUST always start with your domain name. However, you can also pipe delimit additional values after your domain, if you need to.\\n\\nFor example:\n' . c_ws_plugin__s2member_utils_strings::esc_js_sq (esc_attr ($_SERVER["HTTP_HOST"]), 3) . '|cv1|cv2|cv3\'); return false;" tabindex="-1">[?]</a> <input type="button" value="Generate Access Link" onclick="ws_plugin__s2member_paypalRegLinkGenerate();" class="button-primary" /> <img id="ws-plugin--s2member-reg-link-loading" src="' . esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]) . '/images/ajax-loader.gif" alt="" style="display:none;" /></p>' . "\n";
407
  echo '<p' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '>Custom Capabilities (comma-delimited) <a href="#" onclick="alert(\'Optional. This is VERY advanced.\\nSee: s2Member -› API Scripting -› Custom Capabilities.\'); return false;" tabindex="-1">[?]</a> <input type="text" maxlength="125" autocomplete="off" id="ws-plugin--s2member-reg-link-ccaps" size="40" onkeyup="if(this.value.match(/[^a-z_0-9,]/)) this.value = jQuery.trim (jQuery.trim (this.value).replace (/[ \-]/g, \'_\').replace (/[^a-z_0-9,]/gi, \'\').toLowerCase ());" /></p>' . "\n";
408
  echo '<p>Fixed Term Length (for Buy Now transactions): <input type="text" autocomplete="off" id="ws-plugin--s2member-reg-link-fixed-term" value="" size="10" /> <a href="#" onclick="alert(\'If the Customer purchased Membership through a Buy Now transaction (i.e. there is no Initial/Trial Period and no recurring charges for ongoing access), you may configure a Fixed Term Length in this field. This way the Customer\\\'s Membership Access is automatically revoked by s2Member at the appropriate time. This will be a numeric value, followed by a space, then a single letter.\\n\\nHere are some examples:\\n\\n1 D (this means 1 Day)\\n1 W (this means 1 Week)\\n1 M (this means 1 Month)\\n1 Y (this means 1 Year)\\n1 L (this means 1 Lifetime)\'); return false;">[?]</a></p>' . "\n";
424
  {
425
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_sp_buttons", get_defined_vars ());
426
 
427
+ echo '<div class="ws-menu-page-group" title="PayPal Specific Post/Page (Buy Now) Buttons">' . "\n";
428
 
429
  echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-buttons-section">' . "\n";
430
  echo '<h3>Button Code Generator For Specific Post/Page Buttons</h3>' . "\n";
431
+ 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";
432
+ 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";
433
+ 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 -› Restriction Options -› Specific Post/Page Access</code>. Once you\'ve configured your Specific Post/Page Restrictions, those Posts/Pages will be available in the menus below.</p>' . "\n";
434
+ 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";
435
+ 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. 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";
436
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_sp_buttons", get_defined_vars ());
437
 
438
  echo '<table class="form-table">' . "\n";
469
 
470
  echo '<p>I want to charge: $<input type="text" autocomplete="off" id="ws-plugin--s2member-sp-amount" value="0.01" size="4" /> / <select id="ws-plugin--s2member-sp-hours">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-sp-hours.php"))) . '</select></p>' . "\n";
471
  echo '<p>Description: <input type="text" autocomplete="off" id="ws-plugin--s2member-sp-desc" value="Description and pricing details here." size="68" /></p>' . "\n";
472
+ 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;" tabindex="-1">[?]</a>: <input type="text" autocomplete="off" id="ws-plugin--s2member-sp-page-style" value="paypal" size="18" /> <select id="ws-plugin--s2member-sp-currency">' . trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/options/paypal-currencies.php"))) . '</select> <input type="button" value="Generate Button Code" onclick="ws_plugin__s2member_paypalSpButtonGenerate();" class="button-primary" /></p>' . "\n";
473
  echo '</form>' . "\n";
474
  echo '</td>' . "\n";
475
 
479
  echo '<td colspan="2">' . "\n";
480
  echo '<form onsubmit="return false;">' . "\n";
481
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_sp_buttons_before_shortcode", get_defined_vars ());
482
+ echo '<strong>WordPress Shortcode:</strong> (recommended for both the WordPress Visual &amp; HTML Editors)<br />' . "\n";
483
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/shortcodes/paypal-sp-checkout-button-shortcode.php")));
484
  $ws_plugin__s2member_temp_s = preg_replace ("/%%custom%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr ($_SERVER["HTTP_HOST"])), $ws_plugin__s2member_temp_s);
485
  echo '<input type="text" autocomplete="off" id="ws-plugin--s2member-sp-shortcode" value="' . format_to_edit ($ws_plugin__s2member_temp_s) . '" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;" />' . "\n";
486
 
487
  echo '<div' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? ' style="display:none;"' : '') . '><br />' . "\n";
488
+ echo '<strong>Resulting PayPal Button Code:</strong> (ultimately, your Shortcode will produce this snippet)<br />' . "\n";
489
  echo '<textarea id="ws-plugin--s2member-sp-button" rows="8" wrap="off" onclick="this.select ();" style="font-family:Consolas, monospace; width:99%;">';
490
  $ws_plugin__s2member_temp_s = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/paypal-sp-checkout-button.php")));
491
  $ws_plugin__s2member_temp_s = preg_replace ("/%%endpoint%%/", c_ws_plugin__s2member_utils_strings::esc_ds (esc_attr (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")), $ws_plugin__s2member_temp_s);
518
  {
519
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_before_sp_links", get_defined_vars ());
520
 
521
+ echo '<div class="ws-menu-page-group" title="PayPal Specific Post/Page Access Links">' . "\n";
522
 
523
  echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-links-section">' . "\n";
524
  echo '<h3>Specific Post/Page Link Generator (for Customer Service)</h3>' . "\n";
573
 
574
  echo '<div class="ws-menu-page-section ws-plugin--s2member-shortcode-attrs-section">' . "\n";
575
  echo '<h3>Shortcode Attributes (Explained In Full Detail)</h3>' . "\n";
576
+ echo '<p>When you generate a Button Code, s2Member will make a <a href="http://codex.wordpress.org/Shortcode_API#Overview" target="_blank" rel="external">Shortcode</a> available to you. Like most Shortcodes for WordPress, s2Member reads Attributes in your Shortcode. These Attributes will be pre-configured by one of s2Member\'s Button Generators automatically; so there really is nothing more you need to do. However, many site owners like to know exactly how these Shortcode Attributes work. Below, is a brief overview of each possible Shortcode Attribute.</p>' . "\n";
577
  do_action ("ws_plugin__s2member_during_paypal_buttons_page_during_left_sections_during_shortcode_attrs", get_defined_vars ());
578
 
579
  echo '<table class="form-table" style="margin-top:0;">' . "\n";
590
  echo '<li><code>dg="0"</code> The Digital Goods directive. s2Member will eventually be integrated with <a href="http://www.s2member.com/paypal-express-co-digitals" target="_blank" rel="external">Digital Goods</a> for inline Express Checkout. But for now, this should always be <code>0</code>.</li>' . "\n";
591
  echo '<li><code>exp="72"</code> Access Expires (in hours). Only valid when <code>sp="1"</code> for Specific Post/Page Access.</li>' . "\n";
592
  echo '<li><code>ids="14"</code> A Post/Page ID#, or a comma-delimited list of IDs. Only valid when <code>sp="1"</code> for Specific Post/Page Access.</li>' . "\n";
593
+ echo '<li><code>image="default"</code> Button Image Location. Possible values: <code>default</code> = use the default PayPal Button, <code>http://...</code> = location of your custom Image.</li>' . "\n";
594
+ echo '<li><code>lang=""</code> Optional 5 character Button Language Code <em>(ake: Locale Code — ex: <code>en_US</code>)</em>. This controls the interface language of the PayPal Button itself. If unspecified, the language defaults to English (i.e. <code>en_US</code>; or to the value set by an optional MO translation file; which translates s2Member overall). See <a href="https://cms.paypal.com/mx/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ECButtonIntegration#id089QD0O0TX4__id08AH904I0YK" target="_blank" rel="external">this list of possible Locale Codes</a>.</li>' . "\n";
595
+ echo '<li><code>lc=""</code> Optional 2 character Country/Locale Code <em>(i.e. Country Code — ex: <code>US</code>)</em>. This controls the interface language used at PayPal during checkout. If unspecified, the language is determined by PayPal when possible, defaulting to <code>US</code> <em>english</em> when not possible. See <a href="https://cms.paypal.com/mx/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ECButtonIntegration#id089QD0O0TX4__id08AH904I0YK" target="_blank" rel="external">this list of possible Country Codes</a>. Not valid when <code>cancel="1"</code>.</li>' . "\n";
596
  echo '<li><code>level="1"</code> Membership Level [1-4] <em>(or, up to the number of configured Levels)</em>. Only valid for Buttons providing paid Membership Level Access.' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' Or, with Independent Custom Capabilities this MUST be set to <code>level="*"</code>, and <code>ccaps=""</code> must NOT be empty <em>(i.e. <code>level="*" ccaps="music,videos"</code>)</em>.') . '</li>' . "\n";
597
  echo '<li><code>modify="0"</code> Modification directive. Only valid w/ Membership Level Access. Possible values: <code>0</code> = allows Customers to only create a new Subscription, <code>1</code> = allows Customers to modify their current Subscription or sign up for a new one, <code>2</code> = allows Customers to only modify their current Subscription.</li>' . "\n";
598
  echo '<li><code>ns="1"</code> The <em>no_shipping</em> directive. Possible values: <code>0</code> = prompt for an address, but do not require one, <code>1</code> = do not prompt for a shipping address, <code>2</code> = prompt for an address, and require one. Not valid when <code>cancel="1"</code>.</li>' . "\n";
599
+ echo '<li><code>output="button"</code> Output Type. Possible values: <code>button</code> = PayPal Button w/hidden inputs, <code>anchor</code> = PayPal Button ( &lt;a&gt; anchor tag ) URL w/ ?query string, <code>url</code> = raw URL w/ ?query string.</li>' . "\n";
600
+ echo '<li><code>ps="paypal"</code> PayPal checkout Page Style. Not valid when <code>cancel="1"</code>.</li>' . "\n";
601
  echo '<li><code>ra="0.01"</code> Regular, Buy Now, and/or Recurring Amount. Must be &gt;= <code>0.01</code>. Not valid when <code>cancel="1"</code>.</li>' . "\n";
602
  echo '<li><code>rp="1"</code> Regular Period. Only valid w/ Membership Level Access' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' and/or Independent Custom Capabilities') . '. Must be &gt;= <code>1</code> (ex: <code>1</code> Week, <code>2</code> Months, <code>1</code> Month, <code>3</code> Days).</li>' . "\n";
603
  echo '<li><code>rt="M"</code> Regular Term. Only valid w/ Membership Level Access' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' and/or Independent Custom Capabilities') . '. Possible values: <code>D</code> = Days, <code>W</code> = Weeks, <code>M</code> = Months, <code>Y</code> = Years, <code>L</code> = Lifetime.</li>' . "\n";
604
  echo '<li><code>rr="1"</code> Recurring directive. Only valid w/ Membership Level Access' . ((is_multisite () && c_ws_plugin__s2member_utils_conds::is_multisite_farm () && !is_main_site ()) ? '' : ' and/or Independent Custom Capabilities') . '. Possible values: <code>0</code> = non-recurring "Subscription" with possible Trial Period for free, or at a different Trial Amount; <code>1</code> = recurring "Subscription" with possible Trial Period for free, or at a different Trial Amount; <code>BN</code> = non-recurring "Buy Now" functionality, no Trial Period possible.</li>' . "\n";
605
+ echo '<li><code>rrt=""</code> Recurring Times <em>(i.e. a fixed number of installments)</em>. Only valid w/ Membership Level Access. When unspecified, any recurring charges will remain ongoing until cancelled, or until payments start failing. If this is set to <code>1 or higher</code> the regular recurring charges will only continue for X billing cycles, depending on what you specify. This is only valid when <code>rr="1"</code> for recurring "Subscriptions". Please note that a fixed number of installments, also means a fixed period of access. If a Customer\'s billing is monthly, and you set <code>rrt="3"</code>, billing will continue for only 3 monthly installments. After that, billing would stop, and their access to the site would be revoked as well <em>(based on your EOT Behavior setting under: s2Member -› PayPal Options)</em>.</li>' . "\n";
606
+ echo '<li><code>rra="1"</code> Reattempt failed payments? Possible values: <code>0</code> = do NOT reattempt billing when/if a recurring payment fails; <code>1</code> = yes, DO reattempt billing when/if a recurring payment fails. With PayPal Standard integration, PayPal will retry a maximum of 2 times when you set <code>rra="1"</code>; after that, a Subscription would be terminated due to Max Failed Payments having been reached. PayPal Standard integration does NOT make it possible to configure Max Failed Payments, it simply defaults to a value of <code>2</code> whenever <code>rra="1"</code>, indicating that you DO want to retry failed payments.</li>' . "\n";
607
  echo '<li><code>sp="0"</code> Specific Post/Page Button. Possible values: <code>0</code> = this is NOT a Specific Post/Page Access Button, <code>1</code> = this IS a Specific Post/Page Access Button.</li>' . "\n";
608
  echo '<li><code>ta="0.00"</code> Trial Amount. Only valid w/ Membership Level Access. Must be <code>0</code> when <code>rt="L"</code> or when <code>rr="BN"</code>.</li>' . "\n";
609
  echo '<li><code>tp="0"</code> Trial Period. Only valid w/ Membership Level Access. Must be <code>0</code> when <code>rt="L"</code> or when <code>rr="BN"</code>.</li>' . "\n";
includes/menu-pages/paypal-ops.inc.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Menu page for the s2Member plugin (PayPal® Options page).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
@@ -20,7 +20,7 @@ if(realpath(__FILE__) === realpath($_SERVER["SCRIPT_FILENAME"]))
20
  if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
21
  {
22
  /**
23
- * Menu page for the s2Member plugin (PayPal® Options page).
24
  *
25
  * @package s2Member\Menu_Pages
26
  * @since 110531
@@ -32,7 +32,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
32
  echo '<div class="wrap ws-menu-page">'."\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>'."\n";
35
- echo '<h2>s2Member® PayPal® Options</h2>'."\n";
36
 
37
  echo '<table class="ws-menu-page-table">'."\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">'."\n";
@@ -49,13 +49,13 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
49
  {
50
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_paypal_account_details", get_defined_vars());
51
 
52
- echo '<div class="ws-menu-page-group" title="PayPal® Account Details">'."\n";
53
 
54
  echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-account-details-section">'."\n";
55
  echo '<a href="http://www.s2member.com/paypal" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/paypal-logo.png" class="ws-menu-page-right" style="width:125px; height:125px; border:0;" alt="." /></a>'."\n";
56
- echo '<h3>PayPal® Account Details (required, if using PayPal®)</h3>'."\n";
57
- echo '<p>This plugin works in conjunction with <a href="http://www.s2member.com/paypal" target="_blank" rel="external">PayPal® Website Payments Standard</a>, for businesses. You do NOT need a PayPal® Pro account. You just need to upgrade your Personal PayPal® account to a Business status, which is free. A PayPal® account can be <a href="http://pages.ebay.com/help/buy/questions/upgrade-paypal-account.html" target="_blank" rel="external">upgraded</a> from a Personal account to a Business account, simply by going to the `Profile` button under the `My Account` tab, selecting the `Personal Business Information` button, and then clicking the `Upgrade Your Account` button. <strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/paypal-account-types/" target="_blank" rel="external">PayPal® Compatibility (Account Types)</a>.</p>'."\n";
58
- echo '<p><em><strong>*PayPal® API Credentials*</strong> Once you have a PayPal® Business account, you\'ll need access to your <a href="http://www.s2member.com/paypal-profile-api-access" target="_blank" rel="external">PayPal® API Credentials</a>. Log into your PayPal® account, and navigate to <code>Profile -› API Access (or Request API Credentials)</code>. You\'ll choose <code>(PayPal® / Request API Signature)</code>.</em></p>'."\n";
59
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_account_details", get_defined_vars());
60
 
61
  echo '<table class="form-table">'."\n";
@@ -64,7 +64,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
64
 
65
  echo '<th>'."\n";
66
  echo '<label for="ws-plugin--s2member-paypal-business">'."\n";
67
- echo 'Your PayPal® EMail Address:'."\n";
68
  echo '</label>'."\n";
69
  echo '</th>'."\n";
70
 
@@ -73,7 +73,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
73
 
74
  echo '<td>'."\n";
75
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_paypal_business" id="ws-plugin--s2member-paypal-business" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"]).'" /><br />'."\n";
76
- echo 'Enter the email address you\'ve associated with your PayPal® Business account.'."\n";
77
  echo '</td>'."\n";
78
 
79
  echo '</tr>'."\n";
@@ -81,7 +81,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
81
 
82
  echo '<th>'."\n";
83
  echo '<label for="ws-plugin--s2member-paypal-api-username">'."\n";
84
- echo 'Your PayPal® API Username:'."\n";
85
  echo '</label>'."\n";
86
  echo '</th>'."\n";
87
 
@@ -90,7 +90,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
90
 
91
  echo '<td>'."\n";
92
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_paypal_api_username" id="ws-plugin--s2member-paypal-api-username" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_username"]).'" /><br />'."\n";
93
- echo 'At PayPal®, see: <code>Profile -› API Access (or Request API Credentials)</code>.'."\n";
94
  echo '</td>'."\n";
95
 
96
  echo '</tr>'."\n";
@@ -98,7 +98,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
98
 
99
  echo '<th>'."\n";
100
  echo '<label for="ws-plugin--s2member-paypal-api-password">'."\n";
101
- echo 'Your PayPal® API Password:'."\n";
102
  echo '</label>'."\n";
103
  echo '</th>'."\n";
104
 
@@ -107,7 +107,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
107
 
108
  echo '<td>'."\n";
109
  echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_paypal_api_password" id="ws-plugin--s2member-paypal-api-password" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_password"]).'" /><br />'."\n";
110
- echo 'At PayPal®, see: <code>Profile -› API Access (or Request API Credentials)</code>.'."\n";
111
  echo '</td>'."\n";
112
 
113
  echo '</tr>'."\n";
@@ -115,7 +115,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
115
 
116
  echo '<th>'."\n";
117
  echo '<label for="ws-plugin--s2member-paypal-api-signature">'."\n";
118
- echo 'Your PayPal® API Signature:'."\n";
119
  echo '</label>'."\n";
120
  echo '</th>'."\n";
121
 
@@ -124,7 +124,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
124
 
125
  echo '<td>'."\n";
126
  echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_paypal_api_signature" id="ws-plugin--s2member-paypal-api-signature" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_signature"]).'" /><br />'."\n";
127
- echo 'At PayPal®, see: <code>Profile -› API Access (or Request API Credentials)</code>.'."\n";
128
  echo '</td>'."\n";
129
 
130
  echo '</tr>'."\n";
@@ -149,7 +149,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
149
 
150
  echo '<td>'."\n";
151
  echo '<input type="radio" name="ws_plugin__s2member_paypal_sandbox" id="ws-plugin--s2member-paypal-sandbox-0" value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-paypal-sandbox-0">No</label> &nbsp;&nbsp;&nbsp; <input type="radio" name="ws_plugin__s2member_paypal_sandbox" id="ws-plugin--s2member-paypal-sandbox-1" value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-paypal-sandbox-1">Yes, enable support for Sandbox testing.</label><br />'."\n";
152
- echo '<em>Only enable this if you\'ve provided Sandbox credentials above.<br />This puts the API, IPN, PDT and Form/Button Generators all into Sandbox mode.<br />See: <a href="http://www.s2member.com/paypal-developers" target="_blank" rel="external">PayPal® Developers</a></em>'."\n";
153
  echo '</td>'."\n";
154
 
155
  echo '</tr>'."\n";
@@ -165,8 +165,8 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
165
  echo '<tr>'."\n";
166
 
167
  echo '<td>'."\n";
168
- echo '<input type="radio" name="ws_plugin__s2member_paypal_btn_encryption" id="ws-plugin--s2member-paypal-btn-encryption-0" value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_btn_encryption"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-paypal-btn-encryption-0">No</label> &nbsp;&nbsp;&nbsp; <input type="radio" name="ws_plugin__s2member_paypal_btn_encryption" id="ws-plugin--s2member-paypal-btn-encryption-1" value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_btn_encryption"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-paypal-btn-encryption-1">Yes, enable PayPal® Button encryption.</label><br />'."\n";
169
- echo '<em>If enabled, all of your PayPal® Button Shortcodes will produce *encrypted* PayPal® Buttons. This improves security against fraudulent transactions. For extra security, you should update your PayPal® account too, under: <code>My Profile -› Website Payment Preferences</code>. You\'ll want to block all non-encrypted payments. <strong>*Note*</strong> this will NOT work until you\'ve supplied s2Member with your PayPal® Email Address, and also with your API Username/Password/Signature.</em>'."\n";
170
  echo '</td>'."\n";
171
 
172
  echo '</tr>'."\n";
@@ -187,7 +187,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
187
  echo '<td>'."\n";
188
  echo '<input type="radio" name="ws_plugin__s2member_gateway_debug_logs" id="ws-plugin--s2member-gateway-debug-logs-0" value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["gateway_debug_logs"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-gateway-debug-logs-0">No</label> &nbsp;&nbsp;&nbsp; <input type="radio" name="ws_plugin__s2member_gateway_debug_logs" id="ws-plugin--s2member-gateway-debug-logs-1" value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["gateway_debug_logs"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-gateway-debug-logs-1">Yes, enable debugging, with API, IPN &amp; Return Page logging.</label><br />'."\n";
189
  echo '<em>This enables API, IPN and Return Page logging. The log files are stored here: <code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["logs_dir"])).'</code></em><br />'."\n";
190
- echo '<em class="ws-menu-page-hilite">If you have any trouble, please review your s2Member® log files for problems. See: <a href="'.esc_attr(admin_url("/admin.php?page=ws-plugin--s2member-logs")).'">Log Viewer</a></em>'."\n";
191
  echo '</td>'."\n";
192
 
193
  echo '</tr>'."\n";
@@ -208,7 +208,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
208
 
209
  echo '<div class="ws-menu-page-hr"></div>'."\n";
210
 
211
- echo '<p><em><strong>*Sandbox Tip*</strong> If you\'re testing your site through a PayPal® Sandbox account, please remember that Email Confirmations from s2Member will NOT be received after a test purchase. s2Member sends its Confirmation Emails to the PayPal® Email Address of the Customer. Since PayPal® Sandbox addresses are usually bogus (for testing), you will have to run live transactions before Email Confirmations from s2Member are received. That being said, all other s2Member functionality CAN be tested through a PayPal® Sandbox account. Email Confirmations are the only hang-up.</em></p>'."\n";
212
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_account_details_after_sandbox_tip", get_defined_vars());
213
  echo '</div>'."\n";
214
 
@@ -221,15 +221,15 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
221
  {
222
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_paypal_payflow_account_details", get_defined_vars());
223
 
224
- echo '<div class="ws-menu-page-group" title="Payflow Account Details">'."\n";
225
 
226
  echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-payflow-account-details-section">'."\n";
227
  echo '<a href="http://www.s2member.com/paypal" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/paypal-logo.png" class="ws-menu-page-right" style="width:125px; height:125px; border:0;" alt="." /></a>'."\n";
228
- echo '<h3>Payflow® Account Details (required, if using Payflow®)</h3>'."\n";
229
- echo '<p>Newer PayPal® Pro accounts come with the Payflow® API for Recurring Billing service. If you have a newer PayPal® Pro account, and you wish to integrate PayPal\'s Recurring Billing service with s2Member® Pro Forms, you will need to fill in the details here. Providing Payflow® API Credentials here, automatically puts s2Member\'s Recurring Billing integration through Pro Forms, into Payflow® mode. Just fill in the details below, and you\'re ready to generate Pro Forms that charge customers on a recurring basis. s2Member® will use the Payflow® API instead of the standard PayPal® Pro API, which is being slowly phased out in favor of Payflow®.</p>'."\n";
230
- echo '<p><em><strong>*Payflow® API Credentials*</strong> Once you have a PayPal® Pro account, you\'ll need access to your <a href="http://www.s2member.com/paypal-profile-api-access" target="_blank" rel="external">Payflow® API Credentials</a>. Log into your PayPal® account, and navigate to <code>Profile -› API Access (or Request API Credentials)</code>. You\'ll choose <code>(Payflow® / API Access)</code>.</em></p>'."\n";
231
- echo '<p><em><strong>*Important Note*</strong> s2Member® always uses the PayPal® Pro API. It can also use the Payflow® API (if details are supplied here). But please note... supplying Payflow® API Credentials here, does NOT mean you can bypass other sections. Please supply s2Member® with ALL of your PayPal® account details.</em></p>'."\n";
232
- echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/paypal-pro-payflow-edition/" target="_blank" rel="external">PayPal® Pro (PayFlow Edition)</a>.</p>'."\n";
233
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_payflow_account_details", get_defined_vars());
234
 
235
  echo '<table class="form-table">'."\n";
@@ -238,7 +238,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
238
 
239
  echo '<th>'."\n";
240
  echo '<label for="ws-plugin--s2member-paypal-payflow-api-username">'."\n";
241
- echo 'Your Payflow® API Username:'."\n";
242
  echo '</label>'."\n";
243
  echo '</th>'."\n";
244
 
@@ -247,7 +247,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
247
 
248
  echo '<td>'."\n";
249
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_paypal_payflow_api_username" id="ws-plugin--s2member-paypal-payflow-api-username" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_payflow_api_username"]).'" /><br />'."\n";
250
- echo 'At PayPal®, see: <code>Profile -› API Access (or Request API Credentials) -› Payflow® API Access</code>.'."\n";
251
  echo '</td>'."\n";
252
 
253
  echo '</tr>'."\n";
@@ -255,7 +255,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
255
 
256
  echo '<th>'."\n";
257
  echo '<label for="ws-plugin--s2member-paypal-payflow-api-password">'."\n";
258
- echo 'Your Payflow® API Password:'."\n";
259
  echo '</label>'."\n";
260
  echo '</th>'."\n";
261
 
@@ -264,7 +264,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
264
 
265
  echo '<td>'."\n";
266
  echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_paypal_payflow_api_password" id="ws-plugin--s2member-paypal-payflow-api-password" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_payflow_api_password"]).'" /><br />'."\n";
267
- echo 'At PayPal®, see: <code>Profile -› API Access (or Request API Credentials) -› Payflow® API Access</code>.'."\n";
268
  echo '</td>'."\n";
269
 
270
  echo '</tr>'."\n";
@@ -272,7 +272,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
272
 
273
  echo '<th>'."\n";
274
  echo '<label for="ws-plugin--s2member-paypal-payflow-api-partner">'."\n";
275
- echo 'Your Payflow® API Partner:'."\n";
276
  echo '</label>'."\n";
277
  echo '</th>'."\n";
278
 
@@ -281,7 +281,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
281
 
282
  echo '<td>'."\n";
283
  echo '<input type="text" name="ws_plugin__s2member_paypal_payflow_api_partner" id="ws-plugin--s2member-paypal-payflow-api-partner" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_payflow_api_partner"]).'" /><br />'."\n";
284
- echo 'At PayPal®, see: <code>Profile -› API Access (or Request API Credentials) -› Payflow® API Access</code>.'."\n";
285
  echo '</td>'."\n";
286
 
287
  echo '</tr>'."\n";
@@ -289,7 +289,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
289
 
290
  echo '<th>'."\n";
291
  echo '<label for="ws-plugin--s2member-paypal-payflow-api-vendor">'."\n";
292
- echo 'Your Payflow® API Vendor:'."\n";
293
  echo '</label>'."\n";
294
  echo '</th>'."\n";
295
 
@@ -298,7 +298,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
298
 
299
  echo '<td>'."\n";
300
  echo '<input type="text" name="ws_plugin__s2member_paypal_payflow_api_vendor" id="ws-plugin--s2member-paypal-payflow-api-vendor" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_payflow_api_vendor"]).'" /><br />'."\n";
301
- echo 'At PayPal®, see: <code>Profile -› API Access (or Request API Credentials) -› Payflow® API Access</code>.'."\n";
302
  echo '</td>'."\n";
303
 
304
  echo '</tr>'."\n";
@@ -316,20 +316,20 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
316
  {
317
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_paypal_ipn", get_defined_vars());
318
 
319
- echo '<div class="ws-menu-page-group" title="PayPal® IPN Integration">'."\n";
320
 
321
  echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-ipn-section">'."\n";
322
- echo '<h3>PayPal® IPN / Instant Payment Notifications (required, please enable)</h3>'."\n";
323
- echo '<p>Log into your PayPal® account and navigate to this section:<br /><code>Account Profile -› Instant Payment Notification Preferences</code></p>'."\n";
324
  echo '<p>Edit your IPN settings &amp; turn IPN Notifications: <strong><code>On</code></strong></p>'."\n";
325
  echo '<p>You\'ll need your IPN URL, which is:<br /><code>'.esc_html(site_url("/?s2member_paypal_notify=1")).'</code></p>'."\n";
326
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_ipn", get_defined_vars());
327
 
328
  echo '<h3>More Information (<a href="#" onclick="jQuery(\'div#ws-plugin--s2member-paypal-ipn-details\').toggle(); return false;" class="ws-dotted-link">click here</a>)</h3>'."\n";
329
  echo '<div id="ws-plugin--s2member-paypal-ipn-details" style="display:none;">'."\n";
330
- echo '<p><em><strong>*Quick Tip*</strong> In addition to the <a href="http://www.s2member.com/paypal-ipn-setup" target="_blank" rel="external">default IPN settings inside your PayPal® account</a>, 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";
331
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_ipn_after_quick_tip", get_defined_vars());
332
- echo '<p><em><strong>*IPN Communications*</strong> You\'ll be happy to know that s2Member handles cancellations, expirations, failed payments, 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, 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";
333
  echo '</div>'."\n";
334
 
335
  echo '<div class="ws-menu-page-hr"></div>'."\n";
@@ -338,7 +338,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
338
  echo '<div id="ws-plugin--s2member-paypal-ipn-proxy-details" style="display:none;">'."\n";
339
  echo '<p>If you\'re using a 3rd-party application that needs to POST simulated IPN transactions to your s2Member installation, you can use this alternate IPN URL, which includes a Proxy Key. This encrypted Proxy Key verifies incoming data being received by s2Member\'s IPN processor. You can change <em>[proxy-gateway]</em> to whatever you like. The <em>[proxy-gateway]</em> value is required. It will be stored by s2Member as the Customer\'s Paid Subscr. Gateway. Your [proxy-gateway] value will also be reflected in s2Member\'s IPN log.</p>'."\n";
340
  echo '<input type="text" autocomplete="off" value="'.format_to_edit(site_url("/?s2member_paypal_notify=1&s2member_paypal_proxy=[proxy-gateway]&s2member_paypal_proxy_verification=".urlencode(c_ws_plugin__s2member_paypal_utilities::paypal_proxy_key_gen()))).'" style="width:99%;" />'."\n";
341
- echo '<p><em>Any 3rd-party application that is sending IPN transactions to your s2Member installation, must ALWAYS include the <code>custom</code> POST variable, and that variable must always start with your installation domain (i.e. custom=<code>'.esc_html($_SERVER["HTTP_HOST"]).'</code>). In addition, the <code>item_number</code> variable, must always match a format that s2Member looks for. Generally speaking, the <code>item_number</code> should be <code>1, 2, 3, or 4</code>, indicating a specific s2Member Level #. However, s2Member also uses some advanced formats in this field. Just to be sure, we suggest creating a PayPal® Button with the s2Member Button Generator, and then taking a look at the Full Button Code to see how s2Member expects <code>item_number</code> to be formatted. Other than the aforementioned exceptions; all other POST variables should follow PayPal® standards. Please see: <a href="http://www.s2member.com/paypal-ipn-pdt-vars" target="_blank" rel="external">PayPal\'s IPN/PDT reference guide</a> for full documentation.</em></p>'."\n";
342
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_ipn_after_proxy", get_defined_vars());
343
  echo '</div>'."\n";
344
  echo '</div>'."\n";
@@ -352,11 +352,11 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
352
  {
353
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_paypal_pdt", get_defined_vars());
354
 
355
- echo '<div class="ws-menu-page-group" title="PayPal® PDT/Auto-Return Integration">'."\n";
356
 
357
  echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-pdt-section">'."\n";
358
- echo '<h3>PayPal® PDT Identity Token (required, please enable)</h3>'."\n";
359
- echo '<p>Log into your PayPal® account and navigate to this section:<br /><code>Account Profile -› Website Payment Preferences</code></p>'."\n";
360
  echo '<p>Turn the Auto-Return feature: <strong><code>On</code></strong></p>'."\n";
361
  echo '<p>You\'ll need your <a href="'.esc_attr(site_url("/?s2member_paypal_return=1&s2member_paypal_proxy=paypal&s2member_paypal_proxy_use=x-preview")).'" target="_blank" rel="external">Auto-Return URL</a>, which is:<br /><code>'.esc_html(site_url("/?s2member_paypal_return=1")).'</code></p>'."\n";
362
  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";
@@ -368,7 +368,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
368
 
369
  echo '<th>'."\n";
370
  echo '<label for="ws-plugin--s2member-paypal-identity-token">'."\n";
371
- echo 'PayPal® PDT Identity Token:'."\n";
372
  echo '</label>'."\n";
373
  echo '</th>'."\n";
374
 
@@ -377,7 +377,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
377
 
378
  echo '<td>'."\n";
379
  echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_paypal_identity_token" id="ws-plugin--s2member-paypal-identity-token" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_identity_token"]).'" /><br />'."\n";
380
- echo 'Your PDT Identity Token will appear under <em>Profile -› Website Payment Preferences</em> in your PayPal® account.'."\n";
381
  echo '</td>'."\n";
382
 
383
  echo '</tr>'."\n";
@@ -388,7 +388,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
388
 
389
  echo '<h3>More Information (<a href="#" onclick="jQuery(\'div#ws-plugin--s2member-paypal-pdt-details\').toggle(); return false;" class="ws-dotted-link">click here</a>)</h3>'."\n";
390
  echo '<div id="ws-plugin--s2member-paypal-pdt-details" style="display:none;">'."\n";
391
- echo '<p><em><strong>*Quick Tip*</strong> In addition to the <a href="http://www.s2member.com/paypal-pdt-setup" target="_blank" rel="external">default Auto-Return/PDT configuration inside your PayPal® account</a>, 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";
392
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_pdt_after_quick_tip", get_defined_vars());
393
  echo '</div>'."\n";
394
 
@@ -409,7 +409,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
409
 
410
  echo '<div class="ws-menu-page-section ws-plugin--s2member-signup-confirmation-email-section">'."\n";
411
  echo '<h3>Signup Confirmation Email (required, but the default works fine)</h3>'."\n";
412
- echo '<p>This email is sent to new Customers after they return from a successful signup at PayPal®. The <strong>primary</strong> purpose of this email, is to provide the Customer with instructions, along with a link to register a Username for their Membership. You may also customize this further, by providing details that are specifically geared to your site.</p>'."\n";
413
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_signup_confirmation_email", get_defined_vars());
414
 
415
  echo '<table class="form-table">'."\n";
@@ -445,7 +445,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
445
 
446
  echo '<td>'."\n";
447
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_signup_email_subject" id="ws-plugin--s2member-signup-email-subject" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_email_subject"]).'" /><br />'."\n";
448
- echo 'Subject Line used in the email sent to a Customer after a successful signup has occurred through PayPal®.'."\n";
449
  echo '</td>'."\n";
450
 
451
  echo '</tr>'."\n";
@@ -462,11 +462,11 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
462
 
463
  echo '<td>'."\n";
464
  echo '<textarea name="ws_plugin__s2member_signup_email_message" id="ws-plugin--s2member-signup-email-message" rows="10">'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_email_message"]).'</textarea><br />'."\n";
465
- echo 'Message Body used in the email sent to a Customer after a successful signup has occurred through PayPal®.<br /><br />'."\n";
466
  echo '<strong>You can also use these special Replacement Codes if you need them:</strong>'."\n";
467
  echo '<ul>'."\n";
468
  echo '<li><code>%%registration_url%%</code> = The full URL (generated by s2Member) where the Customer can get registered.</li>'."\n";
469
- echo '<li><code>%%subscr_id%%</code> = The PayPal® Subscription ID, which remains constant throughout any &amp; all future payments. [ <a href="#" onclick="alert(\'There is one exception. If you are selling Lifetime or Fixed-Term (non-recurring) access, using Buy Now functionality; the %%subscr_id%% is actually set to the Transaction ID for the purchase. PayPal® does not provide a specific Subscription ID for Buy 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";
470
  echo '<li><code>%%initial%%</code> = The Initial Fee charged during signup. If you offered a 100% Free Trial, this will be <code>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 100% Free Trial Period, this will be 0.\'); return false;">?</a> ]</li>'."\n";
471
  echo '<li><code>%%regular%%</code> = The Regular Amount of the Subscription. If you offer something 100% free, this will be <code>0</code>. [ <a href="#" onclick="alert(\'This is how much the Subscription costs after an Initial Period expires. If you did NOT offer an Initial Period at a different price, %%initial%% and %%regular%% will be equal to the same thing.\'); return false;">?</a> ]</li>'."\n";
472
  echo '<li><code>%%recurring%%</code> = This is the amount that will be charged on a recurring basis, or <code>0</code> if non-recurring. [ <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.\'); return false;">?</a> ]</li>'."\n";
@@ -495,7 +495,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
495
 
496
  echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ?
497
  '<div class="ws-menu-page-hr"></div>' . "\n".
498
- '<p style="margin:0;"><strong>PHP Code:</strong> It is also possible to use PHP tags — optional (for developers). If you use PHP tags, please run a test email with <code>&lt;?php print_r(get_defined_vars()); ?&gt;</code>. This will give you a full list of all PHP variables available to you in this email. The <code>$paypal</code> variable is the most important one. It contains all of the <code>$_POST</code> variables received from PayPal\'s IPN service — or from an s2Member® Pro Form integration (e.g. <code>$paypal["item_number"]</code>, <code>$paypal["item_name"]</code>, etc). Please note that all Replacement Codes will be parsed first, and then any PHP tags that you\'ve included. Also, please remember that emails are sent in plain text format.</p>'."\n"
499
  : '';
500
  echo '</td>'."\n";
501
 
@@ -517,7 +517,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
517
 
518
  echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-confirmation-email-section">'."\n";
519
  echo '<h3>Specific Post/Page Confirmation Email (required, but the default works fine)</h3>'."\n";
520
- 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 -› Restriction 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";
521
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_sp_confirmation_email", get_defined_vars());
522
 
523
  echo '<table class="form-table">'."\n";
@@ -553,7 +553,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
553
 
554
  echo '<td>'."\n";
555
  echo '<input type="text" autocomplete="off" 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";
556
- 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";
557
  echo '</td>'."\n";
558
 
559
  echo '</tr>'."\n";
@@ -570,12 +570,12 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
570
 
571
  echo '<td>'."\n";
572
  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";
573
- 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";
574
  echo '<strong>You can also use these special Replacement Codes if you need them:</strong>'."\n";
575
  echo '<ul>'."\n";
576
  echo '<li><code>%%sp_access_url%%</code> = The full URL (generated by s2Member) where the Customer can gain access.</li>'."\n";
577
  echo '<li><code>%%sp_access_exp%%</code> = Human readable expiration for <code>%%sp_access_url%%</code>. Ex: <em>(link expires in <code>%%sp_access_exp%%</code>)</em>.</li>'."\n";
578
- echo '<li><code>%%txn_id%%</code> = The PayPal® Transaction ID. PayPal® assigns a unique identifier for every purchase.</li>'."\n";
579
  echo '<li><code>%%amount%%</code> = The full Amount that you charged for Specific Post/Page Access. This value will <code>always be > 0</code>.</li>'."\n";
580
  echo '<li><code>%%first_name%%</code> = The First Name of the Customer who purchased Specific Post/Page Access.</li>'."\n";
581
  echo '<li><code>%%last_name%%</code> = The Last Name of the Customer who purchased Specific Post/Page Access.</li>'."\n";
@@ -597,7 +597,7 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
597
 
598
  echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ?
599
  '<div class="ws-menu-page-hr"></div>' . "\n".
600
- '<p style="margin:0;"><strong>PHP Code:</strong> It is also possible to use PHP tags — optional (for developers). If you use PHP tags, please run a test email with <code>&lt;?php print_r(get_defined_vars()); ?&gt;</code>. This will give you a full list of all PHP variables available to you in this email. The <code>$paypal</code> variable is the most important one. It contains all of the <code>$_POST</code> variables received from PayPal\'s IPN service — or from an s2Member® Pro Form integration (e.g. <code>$paypal["item_number"]</code>, <code>$paypal["item_name"]</code>, etc). Please note that all Replacement Codes will be parsed first, and then any PHP tags that you\'ve included. Also, please remember that emails are sent in plain text format.</p>'."\n"
601
  : '';
602
  echo '</td>'."\n";
603
 
@@ -618,10 +618,10 @@ if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
618
  echo '<div class="ws-menu-page-group" title="Automatic EOT Behavior">'."\n";
619
 
620
  echo '<div class="ws-menu-page-section ws-plugin--s2member-eot-behavior-section">'."\n";
621
- echo '<h3>PayPal® EOT Behavior (required, please choose)</h3>'."\n";
622
  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 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. There are also a few other configurable options here, so please read carefully. These options are all very important.</p>'."\n";
623
- echo '<p><strong>PayPal® IPNs:</strong> The PayPal® IPN service will notify s2Member whenever a Member\'s payments have been failing, and/or whenever a Member\'s Subscription has expired for any reason. Even refunds &amp; chargeback reversals are supported through the IPN service. For example, if you issue a refund to an unhappy Customer through PayPal®, s2Member will eventually 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";
624
- echo '<p><em><strong>*Some Hairy Details*</strong> There might be times whenever you notice that a Member\'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 an EOT (End Of Term) is processed, a refund occurs, a chargeback occurs, or when a cancellation occurs - which would later result in a delayed Auto-EOT by s2Member.</em></p>'."\n";
625
  echo '<p><em>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";
626
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_eot_behavior", get_defined_vars());
627
 
1
  <?php
2
  /**
3
+ * Menu page for the s2Member plugin (PayPal Options page).
4
  *
5
  * Copyright: © 2009-2011
6
  * {@link http://www.websharks-inc.com/ WebSharks, Inc.}
20
  if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops"))
21
  {
22
  /**
23
+ * Menu page for the s2Member plugin (PayPal Options page).
24
  *
25
  * @package s2Member\Menu_Pages
26
  * @since 110531
32
  echo '<div class="wrap ws-menu-page">'."\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>'."\n";
35
+ echo '<h2>s2Member PayPal Options</h2>'."\n";
36
 
37
  echo '<table class="ws-menu-page-table">'."\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">'."\n";
49
  {
50
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_paypal_account_details", get_defined_vars());
51
 
52
+ echo '<div class="ws-menu-page-group" title="PayPal Account Details">'."\n";
53
 
54
  echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-account-details-section">'."\n";
55
  echo '<a href="http://www.s2member.com/paypal" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/paypal-logo.png" class="ws-menu-page-right" style="width:125px; height:125px; border:0;" alt="." /></a>'."\n";
56
+ echo '<h3>PayPal Account Details (required, if using PayPal)</h3>'."\n";
57
+ echo '<p>This plugin works in conjunction with <a href="http://www.s2member.com/paypal" target="_blank" rel="external">PayPal Website Payments Standard</a>, for businesses. You do NOT need a PayPal Pro account. You just need to upgrade your Personal PayPal account to a Business status, which is free. A PayPal account can be <a href="http://pages.ebay.com/help/buy/questions/upgrade-paypal-account.html" target="_blank" rel="external">upgraded</a> from a Personal account to a Business account, simply by going to the `Profile` button under the `My Account` tab, selecting the `Personal Business Information` button, and then clicking the `Upgrade Your Account` button. <strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/paypal-account-types/" target="_blank" rel="external">PayPal Compatibility (Account Types)</a>.</p>'."\n";
58
+ echo '<p><em><strong>*PayPal API Credentials*</strong> Once you have a PayPal Business account, you\'ll need access to your <a href="http://www.s2member.com/paypal-profile-api-access" target="_blank" rel="external">PayPal API Credentials</a>. Log into your PayPal account, and navigate to <code>Profile -› API Access (or Request API Credentials)</code>. You\'ll choose <code>(PayPal / Request API Signature)</code>.</em></p>'."\n";
59
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_account_details", get_defined_vars());
60
 
61
  echo '<table class="form-table">'."\n";
64
 
65
  echo '<th>'."\n";
66
  echo '<label for="ws-plugin--s2member-paypal-business">'."\n";
67
+ echo 'Your PayPal EMail Address:'."\n";
68
  echo '</label>'."\n";
69
  echo '</th>'."\n";
70
 
73
 
74
  echo '<td>'."\n";
75
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_paypal_business" id="ws-plugin--s2member-paypal-business" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"]).'" /><br />'."\n";
76
+ echo 'Enter the email address you\'ve associated with your PayPal Business account.'."\n";
77
  echo '</td>'."\n";
78
 
79
  echo '</tr>'."\n";
81
 
82
  echo '<th>'."\n";
83
  echo '<label for="ws-plugin--s2member-paypal-api-username">'."\n";
84
+ echo 'Your PayPal API Username:'."\n";
85
  echo '</label>'."\n";
86
  echo '</th>'."\n";
87
 
90
 
91
  echo '<td>'."\n";
92
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_paypal_api_username" id="ws-plugin--s2member-paypal-api-username" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_username"]).'" /><br />'."\n";
93
+ echo 'At PayPal, see: <code>Profile -› API Access (or Request API Credentials)</code>.'."\n";
94
  echo '</td>'."\n";
95
 
96
  echo '</tr>'."\n";
98
 
99
  echo '<th>'."\n";
100
  echo '<label for="ws-plugin--s2member-paypal-api-password">'."\n";
101
+ echo 'Your PayPal API Password:'."\n";
102
  echo '</label>'."\n";
103
  echo '</th>'."\n";
104
 
107
 
108
  echo '<td>'."\n";
109
  echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_paypal_api_password" id="ws-plugin--s2member-paypal-api-password" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_password"]).'" /><br />'."\n";
110
+ echo 'At PayPal, see: <code>Profile -› API Access (or Request API Credentials)</code>.'."\n";
111
  echo '</td>'."\n";
112
 
113
  echo '</tr>'."\n";
115
 
116
  echo '<th>'."\n";
117
  echo '<label for="ws-plugin--s2member-paypal-api-signature">'."\n";
118
+ echo 'Your PayPal API Signature:'."\n";
119
  echo '</label>'."\n";
120
  echo '</th>'."\n";
121
 
124
 
125
  echo '<td>'."\n";
126
  echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_paypal_api_signature" id="ws-plugin--s2member-paypal-api-signature" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_api_signature"]).'" /><br />'."\n";
127
+ echo 'At PayPal, see: <code>Profile -› API Access (or Request API Credentials)</code>.'."\n";
128
  echo '</td>'."\n";
129
 
130
  echo '</tr>'."\n";
149
 
150
  echo '<td>'."\n";
151
  echo '<input type="radio" name="ws_plugin__s2member_paypal_sandbox" id="ws-plugin--s2member-paypal-sandbox-0" value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-paypal-sandbox-0">No</label> &nbsp;&nbsp;&nbsp; <input type="radio" name="ws_plugin__s2member_paypal_sandbox" id="ws-plugin--s2member-paypal-sandbox-1" value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-paypal-sandbox-1">Yes, enable support for Sandbox testing.</label><br />'."\n";
152
+ echo '<em>Only enable this if you\'ve provided Sandbox credentials above.<br />This puts the API, IPN, PDT and Form/Button Generators all into Sandbox mode.<br />See: <a href="http://www.s2member.com/paypal-developers" target="_blank" rel="external">PayPal Developers</a></em>'."\n";
153
  echo '</td>'."\n";
154
 
155
  echo '</tr>'."\n";
165
  echo '<tr>'."\n";
166
 
167
  echo '<td>'."\n";
168
+ echo '<input type="radio" name="ws_plugin__s2member_paypal_btn_encryption" id="ws-plugin--s2member-paypal-btn-encryption-0" value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_btn_encryption"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-paypal-btn-encryption-0">No</label> &nbsp;&nbsp;&nbsp; <input type="radio" name="ws_plugin__s2member_paypal_btn_encryption" id="ws-plugin--s2member-paypal-btn-encryption-1" value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_btn_encryption"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-paypal-btn-encryption-1">Yes, enable PayPal Button encryption.</label><br />'."\n";
169
+ echo '<em>If enabled, all of your PayPal Button Shortcodes will produce *encrypted* PayPal Buttons. This improves security against fraudulent transactions. For extra security, you should update your PayPal account too, under: <code>My Profile -› Website Payment Preferences</code>. You\'ll want to block all non-encrypted payments. <strong>*Note*</strong> this will NOT work until you\'ve supplied s2Member with your PayPal Email Address, and also with your API Username/Password/Signature.</em>'."\n";
170
  echo '</td>'."\n";
171
 
172
  echo '</tr>'."\n";
187
  echo '<td>'."\n";
188
  echo '<input type="radio" name="ws_plugin__s2member_gateway_debug_logs" id="ws-plugin--s2member-gateway-debug-logs-0" value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["gateway_debug_logs"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-gateway-debug-logs-0">No</label> &nbsp;&nbsp;&nbsp; <input type="radio" name="ws_plugin__s2member_gateway_debug_logs" id="ws-plugin--s2member-gateway-debug-logs-1" value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["gateway_debug_logs"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-gateway-debug-logs-1">Yes, enable debugging, with API, IPN &amp; Return Page logging.</label><br />'."\n";
189
  echo '<em>This enables API, IPN and Return Page logging. The log files are stored here: <code>'.esc_html(c_ws_plugin__s2member_utils_dirs::doc_root_path($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["logs_dir"])).'</code></em><br />'."\n";
190
+ echo '<em class="ws-menu-page-hilite">If you have any trouble, please review your s2Member log files for problems. See: <a href="'.esc_attr(admin_url("/admin.php?page=ws-plugin--s2member-logs")).'">Log Viewer</a></em>'."\n";
191
  echo '</td>'."\n";
192
 
193
  echo '</tr>'."\n";
208
 
209
  echo '<div class="ws-menu-page-hr"></div>'."\n";
210
 
211
+ echo '<p><em><strong>*Sandbox Tip*</strong> If you\'re testing your site through a PayPal Sandbox account, please remember that Email Confirmations from s2Member will NOT be received after a test purchase. s2Member sends its Confirmation Emails to the PayPal Email Address of the Customer. Since PayPal Sandbox addresses are usually bogus (for testing), you will have to run live transactions before Email Confirmations from s2Member are received. That being said, all other s2Member functionality CAN be tested through a PayPal Sandbox account. Email Confirmations are the only hang-up.</em></p>'."\n";
212
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_account_details_after_sandbox_tip", get_defined_vars());
213
  echo '</div>'."\n";
214
 
221
  {
222
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_paypal_payflow_account_details", get_defined_vars());
223
 
224
+ echo '<div class="ws-menu-page-group" title="Payflow Account Details">'."\n";
225
 
226
  echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-payflow-account-details-section">'."\n";
227
  echo '<a href="http://www.s2member.com/paypal" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/images/paypal-logo.png" class="ws-menu-page-right" style="width:125px; height:125px; border:0;" alt="." /></a>'."\n";
228
+ echo '<h3>Payflow Account Details (required, if using Payflow)</h3>'."\n";
229
+ echo '<p>Newer PayPal Pro accounts come with the Payflow API for Recurring Billing service. If you have a newer PayPal Pro account, and you wish to integrate PayPal\'s Recurring Billing service with s2Member Pro Forms, you will need to fill in the details here. Providing Payflow API Credentials here, automatically puts s2Member\'s Recurring Billing integration through Pro Forms, into Payflow mode. Just fill in the details below, and you\'re ready to generate Pro Forms that charge customers on a recurring basis. s2Member will use the Payflow API instead of the standard PayPal Pro API, which is being slowly phased out in favor of Payflow.</p>'."\n";
230
+ echo '<p><em><strong>*Payflow API Credentials*</strong> Once you have a PayPal Pro account, you\'ll need access to your <a href="http://www.s2member.com/paypal-profile-api-access" target="_blank" rel="external">Payflow API Credentials</a>. Log into your PayPal account, and navigate to <code>Profile -› API Access (or Request API Credentials)</code>. You\'ll choose <code>(Payflow / API Access)</code>.</em></p>'."\n";
231
+ echo '<p><em><strong>*Important Note*</strong> s2Member always uses the PayPal Pro API. It can also use the Payflow API (if details are supplied here). But please note... supplying Payflow API Credentials here, does NOT mean you can bypass other sections. Please supply s2Member with ALL of your PayPal account details.</em></p>'."\n";
232
+ echo '<p><strong>See also:</strong> This KB article: <a href="http://www.s2member.com/kb/paypal-pro-payflow-edition/" target="_blank" rel="external">PayPal Pro (PayFlow Edition)</a>.</p>'."\n";
233
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_payflow_account_details", get_defined_vars());
234
 
235
  echo '<table class="form-table">'."\n";
238
 
239
  echo '<th>'."\n";
240
  echo '<label for="ws-plugin--s2member-paypal-payflow-api-username">'."\n";
241
+ echo 'Your Payflow API Username:'."\n";
242
  echo '</label>'."\n";
243
  echo '</th>'."\n";
244
 
247
 
248
  echo '<td>'."\n";
249
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_paypal_payflow_api_username" id="ws-plugin--s2member-paypal-payflow-api-username" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_payflow_api_username"]).'" /><br />'."\n";
250
+ echo 'At PayPal, see: <code>Profile -› API Access (or Request API Credentials) -› Payflow API Access</code>.'."\n";
251
  echo '</td>'."\n";
252
 
253
  echo '</tr>'."\n";
255
 
256
  echo '<th>'."\n";
257
  echo '<label for="ws-plugin--s2member-paypal-payflow-api-password">'."\n";
258
+ echo 'Your Payflow API Password:'."\n";
259
  echo '</label>'."\n";
260
  echo '</th>'."\n";
261
 
264
 
265
  echo '<td>'."\n";
266
  echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_paypal_payflow_api_password" id="ws-plugin--s2member-paypal-payflow-api-password" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_payflow_api_password"]).'" /><br />'."\n";
267
+ echo 'At PayPal, see: <code>Profile -› API Access (or Request API Credentials) -› Payflow API Access</code>.'."\n";
268
  echo '</td>'."\n";
269
 
270
  echo '</tr>'."\n";
272
 
273
  echo '<th>'."\n";
274
  echo '<label for="ws-plugin--s2member-paypal-payflow-api-partner">'."\n";
275
+ echo 'Your Payflow API Partner:'."\n";
276
  echo '</label>'."\n";
277
  echo '</th>'."\n";
278
 
281
 
282
  echo '<td>'."\n";
283
  echo '<input type="text" name="ws_plugin__s2member_paypal_payflow_api_partner" id="ws-plugin--s2member-paypal-payflow-api-partner" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_payflow_api_partner"]).'" /><br />'."\n";
284
+ echo 'At PayPal, see: <code>Profile -› API Access (or Request API Credentials) -› Payflow API Access</code>.'."\n";
285
  echo '</td>'."\n";
286
 
287
  echo '</tr>'."\n";
289
 
290
  echo '<th>'."\n";
291
  echo '<label for="ws-plugin--s2member-paypal-payflow-api-vendor">'."\n";
292
+ echo 'Your Payflow API Vendor:'."\n";
293
  echo '</label>'."\n";
294
  echo '</th>'."\n";
295
 
298
 
299
  echo '<td>'."\n";
300
  echo '<input type="text" name="ws_plugin__s2member_paypal_payflow_api_vendor" id="ws-plugin--s2member-paypal-payflow-api-vendor" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_payflow_api_vendor"]).'" /><br />'."\n";
301
+ echo 'At PayPal, see: <code>Profile -› API Access (or Request API Credentials) -› Payflow API Access</code>.'."\n";
302
  echo '</td>'."\n";
303
 
304
  echo '</tr>'."\n";
316
  {
317
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_paypal_ipn", get_defined_vars());
318
 
319
+ echo '<div class="ws-menu-page-group" title="PayPal IPN Integration">'."\n";
320
 
321
  echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-ipn-section">'."\n";
322
+ echo '<h3>PayPal IPN / Instant Payment Notifications (required, please enable)</h3>'."\n";
323
+ echo '<p>Log into your PayPal account and navigate to this section:<br /><code>Account Profile -› Instant Payment Notification Preferences</code></p>'."\n";
324
  echo '<p>Edit your IPN settings &amp; turn IPN Notifications: <strong><code>On</code></strong></p>'."\n";
325
  echo '<p>You\'ll need your IPN URL, which is:<br /><code>'.esc_html(site_url("/?s2member_paypal_notify=1")).'</code></p>'."\n";
326
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_ipn", get_defined_vars());
327
 
328
  echo '<h3>More Information (<a href="#" onclick="jQuery(\'div#ws-plugin--s2member-paypal-ipn-details\').toggle(); return false;" class="ws-dotted-link">click here</a>)</h3>'."\n";
329
  echo '<div id="ws-plugin--s2member-paypal-ipn-details" style="display:none;">'."\n";
330
+ echo '<p><em><strong>*Quick Tip*</strong> In addition to the <a href="http://www.s2member.com/paypal-ipn-setup" target="_blank" rel="external">default IPN settings inside your PayPal account</a>, 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";
331
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_ipn_after_quick_tip", get_defined_vars());
332
+ echo '<p><em><strong>*IPN Communications*</strong> You\'ll be happy to know that s2Member handles cancellations, expirations, failed payments, 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, 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";
333
  echo '</div>'."\n";
334
 
335
  echo '<div class="ws-menu-page-hr"></div>'."\n";
338
  echo '<div id="ws-plugin--s2member-paypal-ipn-proxy-details" style="display:none;">'."\n";
339
  echo '<p>If you\'re using a 3rd-party application that needs to POST simulated IPN transactions to your s2Member installation, you can use this alternate IPN URL, which includes a Proxy Key. This encrypted Proxy Key verifies incoming data being received by s2Member\'s IPN processor. You can change <em>[proxy-gateway]</em> to whatever you like. The <em>[proxy-gateway]</em> value is required. It will be stored by s2Member as the Customer\'s Paid Subscr. Gateway. Your [proxy-gateway] value will also be reflected in s2Member\'s IPN log.</p>'."\n";
340
  echo '<input type="text" autocomplete="off" value="'.format_to_edit(site_url("/?s2member_paypal_notify=1&s2member_paypal_proxy=[proxy-gateway]&s2member_paypal_proxy_verification=".urlencode(c_ws_plugin__s2member_paypal_utilities::paypal_proxy_key_gen()))).'" style="width:99%;" />'."\n";
341
+ echo '<p><em>Any 3rd-party application that is sending IPN transactions to your s2Member installation, must ALWAYS include the <code>custom</code> POST variable, and that variable must always start with your installation domain (i.e. custom=<code>'.esc_html($_SERVER["HTTP_HOST"]).'</code>). In addition, the <code>item_number</code> variable, must always match a format that s2Member looks for. Generally speaking, the <code>item_number</code> should be <code>1, 2, 3, or 4</code>, indicating a specific s2Member Level #. However, s2Member also uses some advanced formats in this field. Just to be sure, we suggest creating a PayPal Button with the s2Member Button Generator, and then taking a look at the Full Button Code to see how s2Member expects <code>item_number</code> to be formatted. Other than the aforementioned exceptions; all other POST variables should follow PayPal standards. Please see: <a href="http://www.s2member.com/paypal-ipn-pdt-vars" target="_blank" rel="external">PayPal\'s IPN/PDT reference guide</a> for full documentation.</em></p>'."\n";
342
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_ipn_after_proxy", get_defined_vars());
343
  echo '</div>'."\n";
344
  echo '</div>'."\n";
352
  {
353
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_paypal_pdt", get_defined_vars());
354
 
355
+ echo '<div class="ws-menu-page-group" title="PayPal PDT/Auto-Return Integration">'."\n";
356
 
357
  echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-pdt-section">'."\n";
358
+ echo '<h3>PayPal PDT Identity Token (required, please enable)</h3>'."\n";
359
+ echo '<p>Log into your PayPal account and navigate to this section:<br /><code>Account Profile -› Website Payment Preferences</code></p>'."\n";
360
  echo '<p>Turn the Auto-Return feature: <strong><code>On</code></strong></p>'."\n";
361
  echo '<p>You\'ll need your <a href="'.esc_attr(site_url("/?s2member_paypal_return=1&s2member_paypal_proxy=paypal&s2member_paypal_proxy_use=x-preview")).'" target="_blank" rel="external">Auto-Return URL</a>, which is:<br /><code>'.esc_html(site_url("/?s2member_paypal_return=1")).'</code></p>'."\n";
362
  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";
368
 
369
  echo '<th>'."\n";
370
  echo '<label for="ws-plugin--s2member-paypal-identity-token">'."\n";
371
+ echo 'PayPal PDT Identity Token:'."\n";
372
  echo '</label>'."\n";
373
  echo '</th>'."\n";
374
 
377
 
378
  echo '<td>'."\n";
379
  echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_paypal_identity_token" id="ws-plugin--s2member-paypal-identity-token" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_identity_token"]).'" /><br />'."\n";
380
+ echo 'Your PDT Identity Token will appear under <em>Profile -› Website Payment Preferences</em> in your PayPal account.'."\n";
381
  echo '</td>'."\n";
382
 
383
  echo '</tr>'."\n";
388
 
389
  echo '<h3>More Information (<a href="#" onclick="jQuery(\'div#ws-plugin--s2member-paypal-pdt-details\').toggle(); return false;" class="ws-dotted-link">click here</a>)</h3>'."\n";
390
  echo '<div id="ws-plugin--s2member-paypal-pdt-details" style="display:none;">'."\n";
391
+ echo '<p><em><strong>*Quick Tip*</strong> In addition to the <a href="http://www.s2member.com/paypal-pdt-setup" target="_blank" rel="external">default Auto-Return/PDT configuration inside your PayPal account</a>, 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";
392
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_pdt_after_quick_tip", get_defined_vars());
393
  echo '</div>'."\n";
394
 
409
 
410
  echo '<div class="ws-menu-page-section ws-plugin--s2member-signup-confirmation-email-section">'."\n";
411
  echo '<h3>Signup Confirmation Email (required, but the default works fine)</h3>'."\n";
412
+ echo '<p>This email is sent to new Customers after they return from a successful signup at PayPal. The <strong>primary</strong> purpose of this email, is to provide the Customer with instructions, along with a link to register a Username for their Membership. You may also customize this further, by providing details that are specifically geared to your site.</p>'."\n";
413
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_signup_confirmation_email", get_defined_vars());
414
 
415
  echo '<table class="form-table">'."\n";
445
 
446
  echo '<td>'."\n";
447
  echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_signup_email_subject" id="ws-plugin--s2member-signup-email-subject" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_email_subject"]).'" /><br />'."\n";
448
+ echo 'Subject Line used in the email sent to a Customer after a successful signup has occurred through PayPal.'."\n";
449
  echo '</td>'."\n";
450
 
451
  echo '</tr>'."\n";
462
 
463
  echo '<td>'."\n";
464
  echo '<textarea name="ws_plugin__s2member_signup_email_message" id="ws-plugin--s2member-signup-email-message" rows="10">'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_email_message"]).'</textarea><br />'."\n";
465
+ echo 'Message Body used in the email sent to a Customer after a successful signup has occurred through PayPal.<br /><br />'."\n";
466
  echo '<strong>You can also use these special Replacement Codes if you need them:</strong>'."\n";
467
  echo '<ul>'."\n";
468
  echo '<li><code>%%registration_url%%</code> = The full URL (generated by s2Member) where the Customer can get registered.</li>'."\n";
469
+ echo '<li><code>%%subscr_id%%</code> = The PayPal Subscription ID, which remains constant throughout any &amp; all future payments. [ <a href="#" onclick="alert(\'There is one exception. If you are selling Lifetime or Fixed-Term (non-recurring) access, using Buy Now functionality; the %%subscr_id%% is actually set to the Transaction ID for the purchase. PayPal does not provide a specific Subscription ID for Buy 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";
470
  echo '<li><code>%%initial%%</code> = The Initial Fee charged during signup. If you offered a 100% Free Trial, this will be <code>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 100% Free Trial Period, this will be 0.\'); return false;">?</a> ]</li>'."\n";
471
  echo '<li><code>%%regular%%</code> = The Regular Amount of the Subscription. If you offer something 100% free, this will be <code>0</code>. [ <a href="#" onclick="alert(\'This is how much the Subscription costs after an Initial Period expires. If you did NOT offer an Initial Period at a different price, %%initial%% and %%regular%% will be equal to the same thing.\'); return false;">?</a> ]</li>'."\n";
472
  echo '<li><code>%%recurring%%</code> = This is the amount that will be charged on a recurring basis, or <code>0</code> if non-recurring. [ <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.\'); return false;">?</a> ]</li>'."\n";
495
 
496
  echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ?
497
  '<div class="ws-menu-page-hr"></div>' . "\n".
498
+ '<p style="margin:0;"><strong>PHP Code:</strong> It is also possible to use PHP tags — optional (for developers). If you use PHP tags, please run a test email with <code>&lt;?php print_r(get_defined_vars()); ?&gt;</code>. This will give you a full list of all PHP variables available to you in this email. The <code>$paypal</code> variable is the most important one. It contains all of the <code>$_POST</code> variables received from PayPal\'s IPN service — or from an s2Member Pro Form integration (e.g. <code>$paypal["item_number"]</code>, <code>$paypal["item_name"]</code>, etc). Please note that all Replacement Codes will be parsed first, and then any PHP tags that you\'ve included. Also, please remember that emails are sent in plain text format.</p>'."\n"
499
  : '';
500
  echo '</td>'."\n";
501
 
517
 
518
  echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-confirmation-email-section">'."\n";
519
  echo '<h3>Specific Post/Page Confirmation Email (required, but the default works fine)</h3>'."\n";
520
+ 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 -› Restriction 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";
521
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_sp_confirmation_email", get_defined_vars());
522
 
523
  echo '<table class="form-table">'."\n";
553
 
554
  echo '<td>'."\n";
555
  echo '<input type="text" autocomplete="off" 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";
556
+ 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";
557
  echo '</td>'."\n";
558
 
559
  echo '</tr>'."\n";
570
 
571
  echo '<td>'."\n";
572
  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";
573
+ 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";
574
  echo '<strong>You can also use these special Replacement Codes if you need them:</strong>'."\n";
575
  echo '<ul>'."\n";
576
  echo '<li><code>%%sp_access_url%%</code> = The full URL (generated by s2Member) where the Customer can gain access.</li>'."\n";
577
  echo '<li><code>%%sp_access_exp%%</code> = Human readable expiration for <code>%%sp_access_url%%</code>. Ex: <em>(link expires in <code>%%sp_access_exp%%</code>)</em>.</li>'."\n";
578
+ echo '<li><code>%%txn_id%%</code> = The PayPal Transaction ID. PayPal assigns a unique identifier for every purchase.</li>'."\n";
579
  echo '<li><code>%%amount%%</code> = The full Amount that you charged for Specific Post/Page Access. This value will <code>always be > 0</code>.</li>'."\n";
580
  echo '<li><code>%%first_name%%</code> = The First Name of the Customer who purchased Specific Post/Page Access.</li>'."\n";
581
  echo '<li><code>%%last_name%%</code> = The Last Name of the Customer who purchased Specific Post/Page Access.</li>'."\n";
597
 
598
  echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ?
599
  '<div class="ws-menu-page-hr"></div>' . "\n".
600
+ '<p style="margin:0;"><strong>PHP Code:</strong> It is also possible to use PHP tags — optional (for developers). If you use PHP tags, please run a test email with <code>&lt;?php print_r(get_defined_vars()); ?&gt;</code>. This will give you a full list of all PHP variables available to you in this email. The <code>$paypal</code> variable is the most important one. It contains all of the <code>$_POST</code> variables received from PayPal\'s IPN service — or from an s2Member Pro Form integration (e.g. <code>$paypal["item_number"]</code>, <code>$paypal["item_name"]</code>, etc). Please note that all Replacement Codes will be parsed first, and then any PHP tags that you\'ve included. Also, please remember that emails are sent in plain text format.</p>'."\n"
601
  : '';
602
  echo '</td>'."\n";
603
 
618
  echo '<div class="ws-menu-page-group" title="Automatic EOT Behavior">'."\n";
619
 
620
  echo '<div class="ws-menu-page-section ws-plugin--s2member-eot-behavior-section">'."\n";
621
+ echo '<h3>PayPal EOT Behavior (required, please choose)</h3>'."\n";
622
  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 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. There are also a few other configurable options here, so please read carefully. These options are all very important.</p>'."\n";
623
+ echo '<p><strong>PayPal IPNs:</strong> The PayPal IPN service will notify s2Member whenever a Member\'s payments have been failing, and/or whenever a Member\'s Subscription has expired for any reason. Even refunds &amp; chargeback reversals are supported through the IPN service. For example, if you issue a refund to an unhappy Customer through PayPal, s2Member will eventually 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";
624
+ echo '<p><em><strong>*Some Hairy Details*</strong> There might be times whenever you notice that a Member\'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 an EOT (End Of Term) is processed, a refund occurs, a chargeback occurs, or when a cancellation occurs - which would later result in a delayed Auto-EOT by s2Member.</em></p>'."\n";
625
  echo '<p><em>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";
626
  do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_eot_behavior", get_defined_vars());
627
 
includes/menu-pages/res-ops.inc.php CHANGED
@@ -32,7 +32,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_res_ops"))
32
  echo '<div class="wrap ws-menu-page">' . "\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>' . "\n";
35
- echo '<h2>s2Member® Restriction Options</h2>' . "\n";
36
 
37
  echo '<table class="ws-menu-page-table">' . "\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">' . "\n";
@@ -54,7 +54,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_res_ops"))
54
  echo '<div class="ws-menu-page-section ws-plugin--s2member-post-level-access-section">' . "\n";
55
  echo '<h3>Post Level Access Restrictions (optional)</h3>' . "\n";
56
  echo '<p>Here you can specify Posts that are restricted to certain Membership Access Levels. s2Member also supports Custom <a href="http://codex.wordpress.org/Post_Types" target="_blank" rel="external">Post Types</a> here. If you have a theme or plugin installed, which has enabled Custom Post Types <em>(i.e. Music/Videos or something else)</em>, you can put the IDs for those Posts here.</p>' . "\n";
57
- echo '<p><em><strong>*Note*</strong> Protecting individual Posts, ONLY protects the Permalinks for those Posts. It is still possible for excerpts of protected content to be seen in search results generated by WordPress®, feeds, and Archive views; such as your Home Page, inside a Category listing, or through other queries formulated by your theme. This is the intended functionality. Excerpts are a great way to "tease" public visitors. In other words, public visitors may have access to excerpts introduced by your theme, but any attempt to view the full Post (i.e. the Permalink) will result in an automatic redirect to your Membership Options Page; requiring registration.</em></p>' . "\n";
58
  echo '<p><em><strong>*Note*</strong> If you would like to protect many Posts at once (including Archive views), you can use Category Level Restrictions, Tag Level Restrictions, or have a look down below at s2Member\'s options for "Alternative View Protection", which deals with search results, as well as feeds.</em></p>' . "\n";
59
  echo ((!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) && !$GLOBALS["WS_PLUGIN__"]["wp_show_ids"]) ? '<p><em><strong>*Tip*</strong> Can\'t find your Post IDs? Get <a href="http://wordpress.org/extend/plugins/wp-show-ids/" target="_blank" rel="external">WP Show IDs</a>.</em></p>' . "\n" : '';
60
  do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_during_post_level_access", get_defined_vars ());
@@ -240,7 +240,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_res_ops"))
240
  echo '<div class="ws-menu-page-section ws-plugin--s2member-uri-level-access-section">' . "\n";
241
  echo '<h3>URI Level Access Restrictions (optional)</h3>' . "\n";
242
  echo '<p>Here you can specify URIs <em>(or word fragments found in URIs)</em> that are restricted to certain Membership Access Levels. Control over URIs is a little more complex. This section is intended for advanced webmasters only. That being said, here are the basics... A <code>REQUEST_URI</code>, is the portion of a <code>URL</code> that comes immediately after the domain. This is a URL <code>http://www.example.com/path/to/file.php</code>, and this is the URI: <code>/path/to/file.php</code>. In other words, a <code>REQUEST_URI</code> is the full path to a real <em>(or virtual)</em> directory and/or file on your domain.</p>' . "\n";
243
- echo '<p>In the fields below, you can provide a list <em>(one per line)</em> of URIs on your site that should be off-limits based on Membership Level. You can also use word fragments instead of a full URI. If a word fragment is found anywhere in the URI, it will be protected. Wildcards and other regex patterns are NOT supported here, and therefore you don\'t need to escape special characters or anything. Please note, these ARE caSe sensitive. You must be specific with respect to case sensitivity. The word fragment <code>some-path/</code> would NOT match a URI that contains <code>some-Path/</code>. <em>A few <a href="#" onclick="alert(\'URI Replacement Codes:\\n\\n%%current_user_login%% = The current User\\\'s Username, lowercase.\\n%%current_user_id%% = The current User\\\'s ID.\\n%%current_user_level%% = The current User\\\'s s2Member Level.\\n%%current_user_role%% = The current User\\\'s WordPress® Role.' . ((!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '\\n%%current_user_ccaps%% = The current User\\\'s Custom Capabilities.' : '') . '\\n%%current_user_logins%% = Number of times the current User has logged in.\\n\\nFor example, if you\\\'re using BuddyPress, and want to protect BuddyPress Groups, you could add URI protection, like this: /members/%%current_user_login%%/groups/\'); return false;">Replacement Codes</a> are also supported here.</em></p>' . "\n";
244
  echo '<p><em><strong>*BuddyPress (and similar)*</strong> URI Restrictions work great with plugins like BuddyPress that add new areas to your site (where those new areas are NOT necessarily a Post/Page/Tag/Category). In other words, anytime you\'d like to protect a specific feature offered by BuddyPress (or other plugins), you\'ll need to nail down specific word fragments found in the URIs associated with those areas. For instance, with BuddyPress you might have: [ <a href="#" onclick="alert(\'/members/\\n/groups/\\n/blogs/\\n/activity/\\n/messages/\\n/profile/\\n/friends/\\n/settings/\'); return false;">click for example</a> ].</em></p>' . "\n";
245
  do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_during_uri_level_access", get_defined_vars ());
246
 
@@ -285,8 +285,8 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_res_ops"))
285
 
286
  echo '<div class="ws-menu-page-section ws-plugin--s2member-query-level-access-section">' . "\n";
287
  echo '<h3>Alternative View Protection (optional / experimental)</h3>' . "\n";
288
- echo '<p>s2Member protects Categories, Tags, Posts, Pages, Files, URIs &amp; more. BUT, even with all of those security restrictions, it\'s still possible for protected content excerpts to be seen through XML feeds, in search results generated by WordPress®; and/or <em>(depending on your theme)</em>, possibly in other Archive views; which might include: Posts by Author, Posts by Date, a list of featured items formulated by your theme, OR even through other widgets/plugins adding functionality to your site. ~ We refer to all of these collectively, as "Alternative Views".</p>' . "\n";
289
- echo '<p>Using the options below, you can tell s2Member to protect some <em>(or all)</em> of these "Alternative Views", by filtering WordPress® database queries for you. s2Member can automatically hide protected content that is NOT available to the current User/Member. In other words, s2Member is capable of pre-filtering ALL database queries, so that excerpts of protected content will not be allowed to slip through. This is marked "experimental", because we\'re still testing this against MANY widget/plugin/theme combinations. Please <a href="' . esc_attr (c_ws_plugin__s2member_readmes::parse_readme_value ("Forum URI")) . '" target="_blank">report</a> all bugs.</p>' . "\n";
290
  do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_during_uri_level_access", get_defined_vars ());
291
 
292
  echo '<table class="form-table">' . "\n";
@@ -305,13 +305,13 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_res_ops"))
305
  echo '<td>' . "\n";
306
  echo '<div class="ws-menu-page-scrollbox" style="height:105px;">' . "\n";
307
  echo '<input type="hidden" name="ws_plugin__s2member_filter_wp_query[]" value="update-signal" />' . "\n";
308
- foreach (array ("all" => "<strong>Filter ALL WordPress® queries</strong>; protecting all Alternative Views.", "searches" => "&#9492;&#9472; Searches (hide protected content in search results)", "feeds" => "&#9492;&#9472; Feeds (hide protected content in standard XML/RSS/ATOM feeds)", "comment-feeds" => "&#9492;&#9472; Comment Feeds (hide comments associated with protected content, in comment feeds)", "nav-menus" => "&#9492;&#9472; Nav Menus (hide protected content in menus generated with <em>WordPress® -› Appearance -› Menus</em>)", "pages" => "&#9492;&#9472; Pages (hide protected content in widgets that list Pages)") as $ws_plugin__s2member_temp_s_value => $ws_plugin__s2member_temp_s_label)
309
  echo '<input type="checkbox" name="ws_plugin__s2member_filter_wp_query[]" id="ws-plugin--s2member-filter-wp-query-' . esc_attr (preg_replace ("/[^a-z0-9_\-]/", "-", $ws_plugin__s2member_temp_s_value)) . '" value="' . esc_attr ($ws_plugin__s2member_temp_s_value) . '"' . ((in_array ($ws_plugin__s2member_temp_s_value, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["filter_wp_query"])) ? ' checked="checked"' : '') . ' /> <label for="ws-plugin--s2member-filter-wp-query-' . esc_attr (preg_replace ("/[^a-z0-9_\-]/", "-", $ws_plugin__s2member_temp_s_value)) . '">' . $ws_plugin__s2member_temp_s_label . '</label><br />' . "\n";
310
  echo '</div>' . "\n";
311
  echo '<strong>Attn Developers:</strong> Filters can be suppressed dynamically, using this technique:<br />' . "\n";
312
  echo '<code><a href="http://codex.wordpress.org/Function_Reference/query_posts" target="_blank" rel="external">query_posts</a>("suppress_filters=true");</code><br />' . "\n";
313
  echo '<code><a href="http://codex.wordpress.org/Function_Reference/get_posts" target="_blank" rel="external">get_posts</a>()</code> auto-suppresses filters.<br />' . "\n";
314
- echo 'Also see <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-functions/#src_doc_attach_s2member_query_filters()" target="_blank" rel="external">this article</a> in the s2Member® Codex.' . "\n";
315
  echo '</td>' . "\n";
316
 
317
  echo '</tr>' . "\n";
@@ -332,9 +332,9 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_res_ops"))
332
 
333
  echo '<div class="ws-menu-page-section ws-plugin--s2member-conditionals-section">' . "\n";
334
  echo '<h3>Simple Shortcode Conditionals (optional — to protect only parts of your content)</h3>' . "\n";
335
- echo '<p>s2Member® makes it very simple to protect entire Posts/Pages/Categories/Tags/URIs/etc. This can be accomplished here in your WordPress® Dashboard, using one of the many tools made available on this page. Or, from your Post/Page editing station in WordPress®. We consider this to be point-and-click functionality ~ very easy.</p>'."\n";
336
- echo '<p>s2Member® also makes it pretty simple to protect "parts" of a Post or Page. You can even get creative about what you display to certain Users/Members, based upon your own custom criteria. s2Member\'s Simple Shortcode Conditionals are the key to accomplishing this.</p>'."\n";
337
- echo '<p>Please see this KB article to learn more: <a href="http://www.s2member.com/kb/simple-shortcode-conditionals/" target="_blank" rel="external">s2Member® Simple Shortcode Conditionals</a></p>' . "\n";
338
  do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_during_conditionals", get_defined_vars ());
339
  echo '</div>' . "\n";
340
 
@@ -351,10 +351,10 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_res_ops"))
351
 
352
  echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-access-section">' . "\n";
353
  echo '<h3>Specific Post/Page Access Restrictions (optional)</h3>' . "\n";
354
- echo '<p>s2Member now supports an additional layer of functionality <em>(very powerful)</em>, 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";
355
- 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";
356
- 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";
357
- 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";
358
  echo ((!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) && !$GLOBALS["WS_PLUGIN__"]["wp_show_ids"]) ? '<p><em><strong>*Tip*</strong> Can\'t find your Post/Page IDs? Get <a href="http://wordpress.org/extend/plugins/wp-show-ids/" target="_blank" rel="external">WP Show IDs</a>.</em></p>' . "\n" : '';
359
  do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_during_sp_access", get_defined_vars ());
360
 
@@ -430,7 +430,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_res_ops"))
430
  echo '<option value="0"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_failed_login_attempts"] == 0) ? ' selected="selected"' : '') . '>Allow infinite failed logins (Brute Force Restrictions disabled)</option>' . "\n";
431
  echo '</select><br />' . "\n";
432
  echo 'When/if you change this, you should also <strong>Reset Brute Force Logs</strong> (click button above).' . "\n";
433
- echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '<br /><br />The default period of "30 minutes" could be modified through this WordPress® Filter:<br /><code>ws_plugin__s2member_track_failed_logins__exp_time</code>' . "\n" : '';
434
  echo '</td>' . "\n";
435
 
436
  echo '</tr>' . "\n";
@@ -454,6 +454,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_res_ops"))
454
  echo '<input type="button" id="ws-plugin--s2member-ip-restrictions-reset-button" value="Reset IP Restriction Logs" class="ws-menu-page-right" style="min-width:175px;" />' . "\n";
455
  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 <em>(aka: Username Sharing)</em>. 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 Membership Level Access <em>(account logins)</em>, Specific Post/Page Access, Registration Links, and other secure Entry Points. In all cases, the rules are simple. A single Username, Access Link, and/or Entry Point ... 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 <em>(preventing access)</em> 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. You can fine-tune this behavior, using the options below.</p>' . "\n";
456
  echo '<p><em>*Note* an empty IP address (associated with someone browsing anonymously), is also considered a unique IP address, so it cannot circumvent s2Member\'s security.</em></p>' . "\n";
 
457
  do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_during_ip_restrictions", get_defined_vars ());
458
 
459
  echo '<table class="form-table">' . "\n";
@@ -486,7 +487,7 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_res_ops"))
486
  echo '<option value="100"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 100) ? ' selected="selected"' : '') . '>Allow up to 100 different IPs per Customer ( every ' . $ws_plugin__s2member_temp_s . ' )</option>' . "\n";
487
  echo '<option value="0"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 0) ? ' selected="selected"' : '') . '>Allow infinite IPs (all IP Restrictions are disabled)</option>' . "\n";
488
  echo '</select>' . "\n";
489
- echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '<br />The default period of "30 days" could be modified through this WordPress® Filter:<br /><code>ws_plugin__s2member_ip_restrictions__concurrency_time_per_ip</code>' . "\n" : '';
490
  echo '</td>' . "\n";
491
 
492
  echo '</tr>' . "\n";
@@ -536,6 +537,68 @@ if (!class_exists ("c_ws_plugin__s2member_menu_page_res_ops"))
536
  do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_after_ip_restrictions", get_defined_vars ());
537
  }
538
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  echo '<div class="wrap ws-menu-page">' . "\n";
33
 
34
  echo '<div id="icon-plugins" class="icon32"><br /></div>' . "\n";
35
+ echo '<h2>s2Member Restriction Options</h2>' . "\n";
36
 
37
  echo '<table class="ws-menu-page-table">' . "\n";
38
  echo '<tbody class="ws-menu-page-table-tbody">' . "\n";
54
  echo '<div class="ws-menu-page-section ws-plugin--s2member-post-level-access-section">' . "\n";
55
  echo '<h3>Post Level Access Restrictions (optional)</h3>' . "\n";
56
  echo '<p>Here you can specify Posts that are restricted to certain Membership Access Levels. s2Member also supports Custom <a href="http://codex.wordpress.org/Post_Types" target="_blank" rel="external">Post Types</a> here. If you have a theme or plugin installed, which has enabled Custom Post Types <em>(i.e. Music/Videos or something else)</em>, you can put the IDs for those Posts here.</p>' . "\n";
57
+ echo '<p><em><strong>*Note*</strong> Protecting individual Posts, ONLY protects the Permalinks for those Posts. It is still possible for excerpts of protected content to be seen in search results generated by WordPress, feeds, and Archive views; such as your Home Page, inside a Category listing, or through other queries formulated by your theme. This is the intended functionality. Excerpts are a great way to "tease" public visitors. In other words, public visitors may have access to excerpts introduced by your theme, but any attempt to view the full Post (i.e. the Permalink) will result in an automatic redirect to your Membership Options Page; requiring registration.</em></p>' . "\n";
58
  echo '<p><em><strong>*Note*</strong> If you would like to protect many Posts at once (including Archive views), you can use Category Level Restrictions, Tag Level Restrictions, or have a look down below at s2Member\'s options for "Alternative View Protection", which deals with search results, as well as feeds.</em></p>' . "\n";
59
  echo ((!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) && !$GLOBALS["WS_PLUGIN__"]["wp_show_ids"]) ? '<p><em><strong>*Tip*</strong> Can\'t find your Post IDs? Get <a href="http://wordpress.org/extend/plugins/wp-show-ids/" target="_blank" rel="external">WP Show IDs</a>.</em></p>' . "\n" : '';
60
  do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_during_post_level_access", get_defined_vars ());
240
  echo '<div class="ws-menu-page-section ws-plugin--s2member-uri-level-access-section">' . "\n";
241
  echo '<h3>URI Level Access Restrictions (optional)</h3>' . "\n";
242
  echo '<p>Here you can specify URIs <em>(or word fragments found in URIs)</em> that are restricted to certain Membership Access Levels. Control over URIs is a little more complex. This section is intended for advanced webmasters only. That being said, here are the basics... A <code>REQUEST_URI</code>, is the portion of a <code>URL</code> that comes immediately after the domain. This is a URL <code>http://www.example.com/path/to/file.php</code>, and this is the URI: <code>/path/to/file.php</code>. In other words, a <code>REQUEST_URI</code> is the full path to a real <em>(or virtual)</em> directory and/or file on your domain.</p>' . "\n";
243
+ echo '<p>In the fields below, you can provide a list <em>(one per line)</em> of URIs on your site that should be off-limits based on Membership Level. You can also use word fragments instead of a full URI. If a word fragment is found anywhere in the URI, it will be protected. Wildcards and other regex patterns are NOT supported here, and therefore you don\'t need to escape special characters or anything. Please note, these ARE caSe sensitive. You must be specific with respect to case sensitivity. The word fragment <code>some-path/</code> would NOT match a URI that contains <code>some-Path/</code>. <em>A few <a href="#" onclick="alert(\'URI Replacement Codes:\\n\\n%%current_user_login%% = The current User\\\'s Username, lowercase.\\n%%current_user_id%% = The current User\\\'s ID.\\n%%current_user_level%% = The current User\\\'s s2Member Level.\\n%%current_user_role%% = The current User\\\'s WordPress Role.' . ((!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '\\n%%current_user_ccaps%% = The current User\\\'s Custom Capabilities.' : '') . '\\n%%current_user_logins%% = Number of times the current User has logged in.\\n\\nFor example, if you\\\'re using BuddyPress, and want to protect BuddyPress Groups, you could add URI protection, like this: /members/%%current_user_login%%/groups/\'); return false;">Replacement Codes</a> are also supported here.</em></p>' . "\n";
244
  echo '<p><em><strong>*BuddyPress (and similar)*</strong> URI Restrictions work great with plugins like BuddyPress that add new areas to your site (where those new areas are NOT necessarily a Post/Page/Tag/Category). In other words, anytime you\'d like to protect a specific feature offered by BuddyPress (or other plugins), you\'ll need to nail down specific word fragments found in the URIs associated with those areas. For instance, with BuddyPress you might have: [ <a href="#" onclick="alert(\'/members/\\n/groups/\\n/blogs/\\n/activity/\\n/messages/\\n/profile/\\n/friends/\\n/settings/\'); return false;">click for example</a> ].</em></p>' . "\n";
245
  do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_during_uri_level_access", get_defined_vars ());
246
 
285
 
286
  echo '<div class="ws-menu-page-section ws-plugin--s2member-query-level-access-section">' . "\n";
287
  echo '<h3>Alternative View Protection (optional / experimental)</h3>' . "\n";
288
+ echo '<p>s2Member protects Categories, Tags, Posts, Pages, Files, URIs &amp; more. BUT, even with all of those security restrictions, it\'s still possible for protected content excerpts to be seen through XML feeds, in search results generated by WordPress; and/or <em>(depending on your theme)</em>, possibly in other Archive views; which might include: Posts by Author, Posts by Date, a list of featured items formulated by your theme, OR even through other widgets/plugins adding functionality to your site. ~ We refer to all of these collectively, as "Alternative Views".</p>' . "\n";
289
+ echo '<p>Using the options below, you can tell s2Member to protect some <em>(or all)</em> of these "Alternative Views", by filtering WordPress database queries for you. s2Member can automatically hide protected content that is NOT available to the current User/Member. In other words, s2Member is capable of pre-filtering ALL database queries, so that excerpts of protected content will not be allowed to slip through. This is marked "experimental", because we\'re still testing this against MANY widget/plugin/theme combinations. Please <a href="' . esc_attr (c_ws_plugin__s2member_readmes::parse_readme_value ("Forum URI")) . '" target="_blank">report</a> all bugs.</p>' . "\n";
290
  do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_during_uri_level_access", get_defined_vars ());
291
 
292
  echo '<table class="form-table">' . "\n";
305
  echo '<td>' . "\n";
306
  echo '<div class="ws-menu-page-scrollbox" style="height:105px;">' . "\n";
307
  echo '<input type="hidden" name="ws_plugin__s2member_filter_wp_query[]" value="update-signal" />' . "\n";
308
+ foreach (array ("all" => "<strong>Filter ALL WordPress queries</strong>; protecting all Alternative Views.", "searches" => "&#9492;&#9472; Searches (hide protected content in search results)", "feeds" => "&#9492;&#9472; Feeds (hide protected content in standard XML/RSS/ATOM feeds)", "comment-feeds" => "&#9492;&#9472; Comment Feeds (hide comments associated with protected content, in comment feeds)", "nav-menus" => "&#9492;&#9472; Nav Menus (hide protected content in menus generated with <em>WordPress -› Appearance -› Menus</em>)", "pages" => "&#9492;&#9472; Pages (hide protected content in widgets that list Pages)") as $ws_plugin__s2member_temp_s_value => $ws_plugin__s2member_temp_s_label)
309
  echo '<input type="checkbox" name="ws_plugin__s2member_filter_wp_query[]" id="ws-plugin--s2member-filter-wp-query-' . esc_attr (preg_replace ("/[^a-z0-9_\-]/", "-", $ws_plugin__s2member_temp_s_value)) . '" value="' . esc_attr ($ws_plugin__s2member_temp_s_value) . '"' . ((in_array ($ws_plugin__s2member_temp_s_value, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["filter_wp_query"])) ? ' checked="checked"' : '') . ' /> <label for="ws-plugin--s2member-filter-wp-query-' . esc_attr (preg_replace ("/[^a-z0-9_\-]/", "-", $ws_plugin__s2member_temp_s_value)) . '">' . $ws_plugin__s2member_temp_s_label . '</label><br />' . "\n";
310
  echo '</div>' . "\n";
311
  echo '<strong>Attn Developers:</strong> Filters can be suppressed dynamically, using this technique:<br />' . "\n";
312
  echo '<code><a href="http://codex.wordpress.org/Function_Reference/query_posts" target="_blank" rel="external">query_posts</a>("suppress_filters=true");</code><br />' . "\n";
313
  echo '<code><a href="http://codex.wordpress.org/Function_Reference/get_posts" target="_blank" rel="external">get_posts</a>()</code> auto-suppresses filters.<br />' . "\n";
314
+ echo 'Also see <a href="http://www.s2member.com/codex/stable/s2member/api_functions/package-functions/#src_doc_attach_s2member_query_filters()" target="_blank" rel="external">this article</a> in the s2Member Codex.' . "\n";
315
  echo '</td>' . "\n";
316
 
317
  echo '</tr>' . "\n";
332
 
333
  echo '<div class="ws-menu-page-section ws-plugin--s2member-conditionals-section">' . "\n";
334
  echo '<h3>Simple Shortcode Conditionals (optional — to protect only parts of your content)</h3>' . "\n";
335
+ echo '<p>s2Member makes it very simple to protect entire Posts/Pages/Categories/Tags/URIs/etc. This can be accomplished here in your WordPress Dashboard, using one of the many tools made available on this page. Or, from your Post/Page editing station in WordPress. We consider this to be point-and-click functionality ~ very easy.</p>'."\n";
336
+ echo '<p>s2Member also makes it pretty simple to protect "parts" of a Post or Page. You can even get creative about what you display to certain Users/Members, based upon your own custom criteria. s2Member\'s Simple Shortcode Conditionals are the key to accomplishing this.</p>'."\n";
337
+ echo '<p>Please see this KB article to learn more: <a href="http://www.s2member.com/kb/simple-shortcode-conditionals/" target="_blank" rel="external">s2Member Simple Shortcode Conditionals</a></p>' . "\n";
338
  do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_during_conditionals", get_defined_vars ());
339
  echo '</div>' . "\n";
340
 
351
 
352
  echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-access-section">' . "\n";
353
  echo '<h3>Specific Post/Page Access Restrictions (optional)</h3>' . "\n";
354
+ echo '<p>s2Member now supports an additional layer of functionality <em>(very powerful)</em>, 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";
355
+ 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";
356
+ 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";
357
+ 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";
358
  echo ((!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) && !$GLOBALS["WS_PLUGIN__"]["wp_show_ids"]) ? '<p><em><strong>*Tip*</strong> Can\'t find your Post/Page IDs? Get <a href="http://wordpress.org/extend/plugins/wp-show-ids/" target="_blank" rel="external">WP Show IDs</a>.</em></p>' . "\n" : '';
359
  do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_during_sp_access", get_defined_vars ());
360
 
430
  echo '<option value="0"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_failed_login_attempts"] == 0) ? ' selected="selected"' : '') . '>Allow infinite failed logins (Brute Force Restrictions disabled)</option>' . "\n";
431
  echo '</select><br />' . "\n";
432
  echo 'When/if you change this, you should also <strong>Reset Brute Force Logs</strong> (click button above).' . "\n";
433
+ echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '<br /><br />The default period of "30 minutes" could be modified through this WordPress Filter:<br /><code>ws_plugin__s2member_track_failed_logins__exp_time</code>' . "\n" : '';
434
  echo '</td>' . "\n";
435
 
436
  echo '</tr>' . "\n";
454
  echo '<input type="button" id="ws-plugin--s2member-ip-restrictions-reset-button" value="Reset IP Restriction Logs" class="ws-menu-page-right" style="min-width:175px;" />' . "\n";
455
  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 <em>(aka: Username Sharing)</em>. 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 Membership Level Access <em>(account logins)</em>, Specific Post/Page Access, Registration Links, and other secure Entry Points. In all cases, the rules are simple. A single Username, Access Link, and/or Entry Point ... 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 <em>(preventing access)</em> 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. You can fine-tune this behavior, using the options below.</p>' . "\n";
456
  echo '<p><em>*Note* an empty IP address (associated with someone browsing anonymously), is also considered a unique IP address, so it cannot circumvent s2Member\'s security.</em></p>' . "\n";
457
+ echo '<p><em><strong>Note:</strong> This feature can work with or without <strong>Simultaneous Login Monitoring</strong> (Simultaneous Login Monitoring is available only in s2Member Pro). You can choose to implement both Unique IP Access Restrictions and Simultaneous Login Monitoring together; or just one of these; or neither of them. It\'s a matter of preference.</em></p>' . "\n";
458
  do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_during_ip_restrictions", get_defined_vars ());
459
 
460
  echo '<table class="form-table">' . "\n";
487
  echo '<option value="100"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 100) ? ' selected="selected"' : '') . '>Allow up to 100 different IPs per Customer ( every ' . $ws_plugin__s2member_temp_s . ' )</option>' . "\n";
488
  echo '<option value="0"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_ip_restriction"] == 0) ? ' selected="selected"' : '') . '>Allow infinite IPs (all IP Restrictions are disabled)</option>' . "\n";
489
  echo '</select>' . "\n";
490
+ echo (!is_multisite () || !c_ws_plugin__s2member_utils_conds::is_multisite_farm () || is_main_site ()) ? '<br />The default period of "30 days" could be modified through this WordPress Filter:<br /><code>ws_plugin__s2member_ip_restrictions__concurrency_time_per_ip</code>' . "\n" : '';
491
  echo '</td>' . "\n";
492
 
493
  echo '</tr>' . "\n";
537
  do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_after_ip_restrictions", get_defined_vars ());
538
  }
539
 
540
+ if (apply_filters ("ws_plugin__s2member_during_res_ops_page_during_left_sections_display_slogin_restrictions", c_ws_plugin__s2member_utils_conds::pro_is_installed(), get_defined_vars ()))
541
+ {
542
+ do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_before_slogin_restrictions", get_defined_vars ());
543
+
544
+ echo '<div class="ws-menu-page-group" title="Simultaneous Login Restrictions">' . "\n";
545
+
546
+ echo '<div class="ws-menu-page-section ws-plugin--s2member-slogin-restrictions-section">' . "\n";
547
+ echo '<h3>Simultaneous Login Restrictions (prevents username sharing)</h3>' . "\n";
548
+ 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 Username Sharing. It is NOT likely that you\'ll be attacked in this way, but it\'s not a bad idea to protect your system; just in case somebody tries this.</p>'."\n";
549
+ echo '<p>s2Member\'s Simultaneous Login Monitoring (for Membership Access only); works w/ user account logins <em>(Usernames)</em> to help you prevent a security breach. The rules are simple. A single Username can only have X number of simultaneous logins (as configured below). Once that limit is reached, s2Member assumes there has been a security breach. At that time, s2Member will place a temporary ban <em>(preventing access)</em> and the offending Username will be unable to login until somebody else (who is already logged into the account) has logged-out; clearing the way for someone new.</p>' . "\n";
550
+ echo '<p>This can be a tricky feature to configure, because not everyone actually clicks the "Logout" link obviously, and so it can be challenging to know when someone is still logged into the site and when they\'re not. s2Member monitors simultaneous logins by updating a timer when someone actually logs in; and then again on each page view while they navigate the site. If there is no activity after X amount of time, s2Member\'s Simultaneous Login Monitor considers that person inactive, and will not include them in security checks until they login again, or visit a new page on the site. You can configure the timeout period below. The default value is <code>30 minutes</code> (we recommend a low value to reduce the chance of error).</p>' . "\n";
551
+ echo '<p><em><strong>Note:</strong> This feature can work with or without <strong>Unique IP Access Restrictions</strong> being enabled. You can choose to implement both Unique IP Access Restrictions and Simultaneous Login Monitoring together; or just one of these; or neither of them. It\'s a matter of preference.</em></p>' . "\n";
552
+ do_action ("ws_plugin__s2member_during_res_ops_page_during_left_sections_during_slogin_restrictions", get_defined_vars ());
553
+
554
+ echo '<table class="form-table">' . "\n";
555
+ echo '<tbody>' . "\n";
556
+ echo '<tr>' . "\n";
557
+
558
+ echo '<th>' . "\n";
559
+ echo '<label for="ws-plugin--s2member-max-simultaneous-logins">' . "\n";
560
+ echo 'Max Simultaneous Logins Allowed; for each Username:' . "\n";
561
+ echo '</label>' . "\n";
562
+ echo '</th>' . "\n";
563
+
564
+ echo '</tr>' . "\n";
565
+ echo '<tr>' . "\n";
566
+
567
+ echo '<td>' . "\n";
568
+ echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_max_simultaneous_logins" id="ws-plugin--s2member-max-simultaneous-logins" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_simultaneous_logins"]) . '" /><br />' . "\n";
569
+ echo 'Examples: <code>0</code> (to disable this functionality), <code>1</code> (maximum of 1 login at a time), <code>2</code>, <code>3</code>, <code>10</code>, <code>20</code>, etc.<br />' . "\n";
570
+ echo 'Suggestion: <code>3</code> — the chance to open your site in multiple browsers; but still prevents major security issues.<br />' . "\n";
571
+ echo '</td>' . "\n";
572
+
573
+ echo '</tr>' . "\n";
574
+ echo '<tr>' . "\n";
575
+
576
+ echo '<th>' . "\n";
577
+ echo '<label for="ws-plugin--s2member-max-simultaneous-logins-timeout">' . "\n";
578
+ echo 'Inactivity Timeout Period; this impacts Simultaneous Login Monitoring only.<br />' . "\n";
579
+ echo 'Simultaneous Login Monitoring should assume a Username is logged-out after this amount of time:' . "\n";
580
+ echo '</label>' . "\n";
581
+ echo '</th>' . "\n";
582
+
583
+ echo '</tr>' . "\n";
584
+ echo '<tr>' . "\n";
585
+
586
+ echo '<td>' . "\n";
587
+ echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_max_simultaneous_logins_timeout" id="ws-plugin--s2member-max-simultaneous-logins-timeout" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["max_simultaneous_logins_timeout"]) . '" /><br />' . "\n";
588
+ echo 'Examples: <code>30 minutes</code>, <code>1 hour</code>, <code>2 hours</code>; anything compatible with PHP\'s <a href="http://php.net/manual/en/function.strtotime.php" target="_blank" rel="external