| 1 |
<?php |
| 2 |
// @codingStandardsIgnoreFile |
| 3 |
/** |
| 4 |
* Menu page for the s2Member plugin (PayPal Options page). |
| 5 |
* |
| 6 |
* Copyright: © 2009-2011 |
| 7 |
* {@link http://websharks-inc.com/ WebSharks, Inc.} |
| 8 |
* (coded in the USA) |
| 9 |
* |
| 10 |
* Released under the terms of the GNU General Public License. |
| 11 |
* You should have received a copy of the GNU General Public License, |
| 12 |
* along with this software. In the main directory, see: /licensing/ |
| 13 |
* If not, see: {@link http://www.gnu.org/licenses/}. |
| 14 |
* |
| 15 |
* @package s2Member\Menu_Pages |
| 16 |
* @since 3.0 |
| 17 |
*/ |
| 18 |
if(!defined('WPINC')) // MUST have WordPress. |
| 19 |
exit("Do not access this file directly."); |
| 20 |
|
| 21 |
if(!class_exists("c_ws_plugin__s2member_menu_page_paypal_ops")) |
| 22 |
{ |
| 23 |
/** |
| 24 |
* Menu page for the s2Member plugin (PayPal Options page). |
| 25 |
* |
| 26 |
* @package s2Member\Menu_Pages |
| 27 |
* @since 110531 |
| 28 |
*/ |
| 29 |
class c_ws_plugin__s2member_menu_page_paypal_ops |
| 30 |
{ |
| 31 |
public function __construct() |
| 32 |
{ |
| 33 |
$ppco_webhook_notice = ''; |
| 34 |
$ppco_creds_notice = ''; |
| 35 |
$ppco_cache_notice = ''; |
| 36 |
|
| 37 |
$ppco_r = !empty($_POST) ? $_POST : $_GET; |
| 38 |
if(!empty($ppco_r['s2member_ppco_webhook']) && empty($ppco_r['s2member_ppco_creds_test']) && empty($ppco_r['s2member_ppco_clear_cache']) && current_user_can('manage_options')) |
| 39 |
{ |
| 40 |
if(!empty($ppco_r['_wpnonce']) && wp_verify_nonce((string)$ppco_r['_wpnonce'], 's2member_ppco_webhook')) |
| 41 |
{ |
| 42 |
$env = (!empty($ppco_r['ppco_webhook_env']) && $ppco_r['ppco_webhook_env'] === 'sandbox') ? 'sandbox' : 'live'; |
| 43 |
$env_label = ($env === 'sandbox') ? esc_html__('Sandbox', 's2member') : esc_html__('Live', 's2member'); |
| 44 |
|
| 45 |
$client_id = ''; |
| 46 |
$secret = ''; |
| 47 |
|
| 48 |
if($env === 'sandbox') |
| 49 |
{ |
| 50 |
$client_id = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_client_id"]; |
| 51 |
$secret = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_client_secret"]; |
| 52 |
} |
| 53 |
else // live |
| 54 |
{ |
| 55 |
$client_id = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_client_id"]; |
| 56 |
$secret = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_client_secret"]; |
| 57 |
} |
| 58 |
|
| 59 |
if(!empty($client_id) && !empty($secret)) |
| 60 |
{ |
| 61 |
$scheme = strtolower((string)c_ws_plugin__s2member_utils_urls::parse_url(home_url('/'), PHP_URL_SCHEME)); |
| 62 |
|
| 63 |
//260224 Reverse-proxy/Cloudflare fallback for admin-side HTTPS detection. |
| 64 |
// This only affects the admin gating check here. It does NOT change the webhook URL itself. |
| 65 |
$proxy_https = false; |
| 66 |
if(!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && stripos(strtolower((string)$_SERVER['HTTP_X_FORWARDED_PROTO']), 'https') !== false) |
| 67 |
$proxy_https = true; |
| 68 |
else if(!empty($_SERVER['HTTP_X_FORWARDED_SSL']) && strtolower((string)$_SERVER['HTTP_X_FORWARDED_SSL']) === 'on') |
| 69 |
$proxy_https = true; |
| 70 |
else if(!empty($_SERVER['HTTPS']) && in_array(strtolower((string)$_SERVER['HTTPS']), array('on', '1'), true)) |
| 71 |
$proxy_https = true; |
| 72 |
else if(!empty($_SERVER['HTTP_CF_VISITOR']) && stripos((string)$_SERVER['HTTP_CF_VISITOR'], '"scheme":"https"') !== false) |
| 73 |
$proxy_https = true; |
| 74 |
|
| 75 |
if($scheme !== 'https' && !$proxy_https) |
| 76 |
$ppco_webhook_notice = '<div class="error"><p>'.esc_html__('Unable to create/update PayPal Checkout webhook. PayPal requires an HTTPS (SSL) webhook URL, but your site URL appears to be configured without HTTPS. Please enable SSL and update your WordPress Site URL/Home URL to use https://, then try again.', 's2member').'</p></div>'."\n"; |
| 77 |
else |
| 78 |
{ |
| 79 |
//260216 IMPORTANT: |
| 80 |
// Do not block webhook creation/update based on a server-side "loopback" probe. |
| 81 |
// Many shared hosts/WAFs return false negatives for loopback requests (e.g., HEAD blocked, |
| 82 |
// ModSecurity rules, disabled loopback/outbound HTTP). PayPal can still deliver webhooks |
| 83 |
// successfully from the outside. |
| 84 |
|
| 85 |
$r = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_webhook_upsert($env); |
| 86 |
|
| 87 |
if(!empty($r['id'])) |
| 88 |
{ |
| 89 |
$ppco_webhook_notice = '<div class="updated"><p>'.sprintf(esc_html__('PayPal Checkout %1$s webhook created/updated successfully.', 's2member'), $env_label).'</p></div>'."\n"; |
| 90 |
|
| 91 |
//260824.0507 The persistent warning was rendered before this page action ran; remove that now-resolved copy immediately. |
| 92 |
$ppco_webhook_notice .= '<script>(function(){var e=document.querySelector(".s2member-ppco-webhook-upgrade-notice-'.esc_js($env).'");if(e&&e.closest){e=e.closest(".notice");if(e)e.remove();}})();</script>'."\n"; |
| 93 |
} |
| 94 |
else |
| 95 |
$ppco_webhook_notice = '<div class="error"><p>'.sprintf(esc_html__('Unable to create/update PayPal Checkout %1$s webhook. See the s2Member paypal-checkout.log for details.', 's2member'), $env_label).' <a href="'.esc_attr(admin_url("/admin.php?page=ws-plugin--s2member-logs")).'">'.esc_html__('Log Viewer', 's2member').'</a></p></div>'."\n"; |
| 96 |
} |
| 97 |
} |
| 98 |
else |
| 99 |
$ppco_webhook_notice = '<div class="error"><p>'.sprintf(esc_html__('PayPal Checkout %1$s credentials are not configured.', 's2member'), $env_label).'</p></div>'."\n"; |
| 100 |
} |
| 101 |
else |
| 102 |
$ppco_webhook_notice = '<div class="error"><p>'.esc_html__('Invalid request. Please try again.', 's2member').'</p></div>'."\n"; |
| 103 |
} |
| 104 |
|
| 105 |
// No redirect; display notice inline. |
| 106 |
|
| 107 |
if(!empty($ppco_r['s2member_ppco_creds_test']) && empty($ppco_r['s2member_ppco_webhook']) && empty($ppco_r['s2member_ppco_clear_cache']) && current_user_can('manage_options')) |
| 108 |
{ |
| 109 |
if(!empty($ppco_r['_wpnonce']) && wp_verify_nonce((string)$ppco_r['_wpnonce'], 's2member_ppco_creds_test')) |
| 110 |
{ |
| 111 |
$env = (!empty($ppco_r['ppco_creds_env']) && $ppco_r['ppco_creds_env'] === 'sandbox') ? 'sandbox' : 'live'; |
| 112 |
$env_label = ($env === 'sandbox') ? esc_html__('Sandbox', 's2member') : esc_html__('Live', 's2member'); |
| 113 |
|
| 114 |
$client_id = ''; |
| 115 |
$secret = ''; |
| 116 |
|
| 117 |
if($env === 'sandbox') |
| 118 |
{ |
| 119 |
$client_id = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_client_id"]; |
| 120 |
$secret = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_client_secret"]; |
| 121 |
} |
| 122 |
else // live |
| 123 |
{ |
| 124 |
$client_id = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_client_id"]; |
| 125 |
$secret = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_client_secret"]; |
| 126 |
} |
| 127 |
|
| 128 |
if(!empty($client_id) && !empty($secret)) |
| 129 |
{ |
| 130 |
$ok = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_creds_test($env); |
| 131 |
|
| 132 |
if($ok) |
| 133 |
$ppco_creds_notice = '<div class="updated"><p>'.sprintf(esc_html__('PayPal Checkout %1$s credentials test OK.', 's2member'), $env_label).'</p></div>'."\n"; |
| 134 |
else |
| 135 |
$ppco_creds_notice = '<div class="error"><p>'.sprintf(esc_html__('PayPal Checkout %1$s credentials test failed. Please verify that the Client ID and Secret were copied from the same PayPal %1$s REST app, paste them again, save options, and test again. See the s2Member paypal-checkout.log for details.', 's2member'), $env_label).' <a href="'.esc_attr(admin_url("/admin.php?page=ws-plugin--s2member-logs")).'">'.esc_html__('Log Viewer', 's2member').'</a></p></div>'."\n"; |
| 136 |
} |
| 137 |
else |
| 138 |
$ppco_creds_notice = '<div class="error"><p>'.sprintf(esc_html__('PayPal Checkout %1$s credentials are not configured.', 's2member'), $env_label).'</p></div>'."\n"; |
| 139 |
} |
| 140 |
else |
| 141 |
$ppco_creds_notice = '<div class="error"><p>'.esc_html__('Invalid request. Please try again.', 's2member').'</p></div>'."\n"; |
| 142 |
} |
| 143 |
|
| 144 |
// No redirect; display notice inline. |
| 145 |
|
| 146 |
if(!empty($ppco_r['s2member_ppco_clear_cache']) && empty($ppco_r['s2member_ppco_webhook']) && empty($ppco_r['s2member_ppco_creds_test']) && current_user_can('manage_options')) |
| 147 |
{ |
| 148 |
if(!empty($ppco_r['_wpnonce']) && wp_verify_nonce((string)$ppco_r['_wpnonce'], 's2member_ppco_clear_cache')) |
| 149 |
{ |
| 150 |
$env = (!empty($ppco_r['ppco_clear_env']) && $ppco_r['ppco_clear_env'] === 'sandbox') ? 'sandbox' : 'live'; |
| 151 |
$env_label = ($env === 'sandbox') ? esc_html__('Sandbox', 's2member') : esc_html__('Live', 's2member'); |
| 152 |
|
| 153 |
c_ws_plugin__s2member_paypal_utilities::paypal_checkout_clear_cache($env); |
| 154 |
|
| 155 |
$ppco_cache_notice = '<div class="updated"><p>'.sprintf(esc_html__('PayPal Checkout cache cleared for %1$s.', 's2member'), $env_label).'</p></div>'."\n"; |
| 156 |
} |
| 157 |
else |
| 158 |
$ppco_cache_notice = '<div class="error"><p>'.esc_html__('Invalid request. Please try again.', 's2member').'</p></div>'."\n"; |
| 159 |
} |
| 160 |
|
| 161 |
// No redirect; display notice inline. |
| 162 |
|
| 163 |
echo '<div class="wrap ws-menu-page">'."\n"; |
| 164 |
echo $ppco_webhook_notice; |
| 165 |
echo $ppco_creds_notice; |
| 166 |
echo $ppco_cache_notice; |
| 167 |
|
| 168 |
echo '<div class="wp-header-end"></div>'."\n"; |
| 169 |
|
| 170 |
echo '<div class="ws-menu-page-toolbox">'."\n"; |
| 171 |
c_ws_plugin__s2member_menu_pages_tb::display(); |
| 172 |
echo '</div>'."\n"; |
| 173 |
|
| 174 |
echo '<h2>PayPal Options</h2>'."\n"; |
| 175 |
|
| 176 |
echo '<table class="ws-menu-page-table">'."\n"; |
| 177 |
echo '<tbody class="ws-menu-page-table-tbody">'."\n"; |
| 178 |
echo '<tr class="ws-menu-page-table-tr">'."\n"; |
| 179 |
echo '<td class="ws-menu-page-table-l">'."\n"; |
| 180 |
|
| 181 |
do_action("ws_plugin__s2member_during_paypal_ops_page_before_left_sections_form", get_defined_vars()); |
| 182 |
|
| 183 |
echo '<form method="post" name="ws_plugin__s2member_options_form" id="ws-plugin--s2member-options-form" autocomplete="off">'."\n"; |
| 184 |
echo '<input type="hidden" name="ws_plugin__s2member_options_save" id="ws-plugin--s2member-options-save" value="'.esc_attr(wp_create_nonce("ws-plugin--s2member-options-save")).'" />'."\n"; |
| 185 |
echo '<input type="hidden" name="ws_plugin__s2member_configured" id="ws-plugin--s2member-configured" value="1" />'."\n"; |
| 186 |
|
| 187 |
do_action("ws_plugin__s2member_during_paypal_ops_page_before_left_sections", get_defined_vars()); |
| 188 |
|
| 189 |
if(apply_filters("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_display_paypal_account_details", TRUE, get_defined_vars())) |
| 190 |
{ |
| 191 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_paypal_account_details", get_defined_vars()); |
| 192 |
|
| 193 |
//260106 New PayPal Checkout panel. |
| 194 |
//260824.0507 Allow administrative notices to open and jump directly to the PayPal Checkout panel. |
| 195 |
echo '<div id="ws-plugin--s2member-paypal-checkout"></div>'."\n"; |
| 196 |
echo '<div class="ws-menu-page-group" title="PayPal Checkout (Beta)"'.((!empty($_GET['s2member-open-panel']) && $_GET['s2member-open-panel'] === 'paypal-checkout') ? ' default-state="open"' : '').'>'."\n"; |
| 197 |
|
| 198 |
echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-checkout-account-details-section">'."\n"; |
| 199 |
echo '<a href="https://s2member.com/r/paypal/" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/src/images/paypal-pp-logo-200px.png" class="ws-menu-page-right s2m-ppco-paypal-logo" style="width:250px; max-width:25%; height:auto; margin:0 20px 20px 0;" alt="PayPal" /></a>'."\n"; |
| 200 |
|
| 201 |
echo '<div class="ws-menu-page-notice ws-menu-page-notice-info">'."\n"; |
| 202 |
//260818.2340 PayPal Checkout now powers both Framework buttons and the PayPal option in s2Member Pro-Forms without shortcode edits. |
| 203 |
echo '<p>'.esc_html__('When enabled, existing s2Member PayPal Button shortcodes and s2Member Pro-Forms that offer PayPal are powered by PayPal Checkout without requiring shortcode edits. If disabled, they continue using their existing PayPal Standard or Express Checkout flow.', 's2member').'</p>'."\n"; |
| 204 |
|
| 205 |
echo '<p style="margin:0 0 6px 0;"><strong>'.esc_html__('Quick Setup (Live or Sandbox)', 's2member').'</strong></p>'."\n"; |
| 206 |
echo '<ol style="margin:0 0 0 20px;">'."\n"; |
| 207 |
echo '<li>'.esc_html__('Enable PayPal Checkout below, choose the environment (Live or Sandbox).', 's2member').'</li>'."\n"; |
| 208 |
echo '<li>'.esc_html__('Go to PayPal\'s “Apps & Credentials”, and click “Create App” for your site (s2Member).', 's2member').' <a href="https://developer.paypal.com/dashboard/applications/live" target="_blank" rel="external">'.esc_html__('Live', 's2member').'</a> / <a href="https://developer.paypal.com/dashboard/applications/sandbox" target="_blank" rel="external">'.esc_html__('Sandbox', 's2member').'</a></li>'."\n"; |
| 209 |
echo '<li>'.esc_html__('Copy the app\'s Client ID and Secret (REST API, not NVP) and paste them below.', 's2member').'</li>'."\n"; |
| 210 |
echo '<li>'.esc_html__('Click “Save All Changes”.', 's2member').'</li>'."\n"; |
| 211 |
echo '<li>'.esc_html__('Click “Test Credentials” to verify the saved Client ID and Secret are correct.', 's2member').'</li>'."\n"; |
| 212 |
echo '<li>'.esc_html__('Click “Create/Update Webhook” to register your webhook URL with PayPal and populate the Webhook ID field.', 's2member').'</li>'."\n"; |
| 213 |
echo '<li>'.esc_html__('Click “Test Webhook Endpoint” to check it.', 's2member').'</li>'."\n"; |
| 214 |
echo '</ol>'."\n"; |
| 215 |
|
| 216 |
echo '<p style="margin:12px 0 0 0;"><strong>'.esc_html__('Useful PayPal links', 's2member').'</strong></p>'."\n"; |
| 217 |
echo '<ul style="margin:0 0 0 20px; list-style:disc;">'."\n"; |
| 218 |
echo '<li><a href="https://developer.paypal.com/api/rest/webhooks/" target="_blank" rel="external">'.esc_html__('Webhooks overview (PayPal docs)', 's2member').'</a></li>'."\n"; |
| 219 |
echo '<li><a href="https://developer.paypal.com/api/rest/webhooks/simulator/" target="_blank" rel="external">'.esc_html__('Webhooks simulator (connectivity testing)', 's2member').'</a></li>'."\n"; |
| 220 |
echo '<li><a href="https://developer.paypal.com/api/rest/webhooks/events-dashboard/" target="_blank" rel="external">'.esc_html__('Webhooks Events dashboard (view/re-deliver events)', 's2member').'</a></li>'."\n"; |
| 221 |
echo '</ul>'."\n"; |
| 222 |
|
| 223 |
echo '</div>'."\n"; |
| 224 |
|
| 225 |
echo '<p><em>'.esc_html__('Leave these fields blank to continue using your existing PayPal Standard and Express Checkout integrations.', 's2member').'</em></p>'."\n"; |
| 226 |
|
| 227 |
$ppco_https_ready = true; |
| 228 |
$ppco_https_reason = ''; |
| 229 |
|
| 230 |
$ppco_https_scheme = strtolower((string)c_ws_plugin__s2member_utils_urls::parse_url(home_url('/'), PHP_URL_SCHEME)); |
| 231 |
|
| 232 |
//260224 Reverse-proxy/Cloudflare fallback for admin-side HTTPS detection. |
| 233 |
// This keeps PayPal Checkout configuration available when WordPress is behind a proxy |
| 234 |
// and the current admin request is clearly HTTPS at the edge. |
| 235 |
$ppco_proxy_https = false; |
| 236 |
if(!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && stripos(strtolower((string)$_SERVER['HTTP_X_FORWARDED_PROTO']), 'https') !== false) |
| 237 |
$ppco_proxy_https = true; |
| 238 |
else if(!empty($_SERVER['HTTP_X_FORWARDED_SSL']) && strtolower((string)$_SERVER['HTTP_X_FORWARDED_SSL']) === 'on') |
| 239 |
$ppco_proxy_https = true; |
| 240 |
else if(!empty($_SERVER['HTTPS']) && in_array(strtolower((string)$_SERVER['HTTPS']), array('on', '1'), true)) |
| 241 |
$ppco_proxy_https = true; |
| 242 |
else if(!empty($_SERVER['HTTP_CF_VISITOR']) && stripos((string)$_SERVER['HTTP_CF_VISITOR'], '"scheme":"https"') !== false) |
| 243 |
$ppco_proxy_https = true; |
| 244 |
|
| 245 |
if($ppco_https_scheme !== 'https' && !$ppco_proxy_https) |
| 246 |
{ |
| 247 |
$ppco_https_ready = false; |
| 248 |
$ppco_https_reason = __('Your WordPress Site URL/Home URL is currently not configured for HTTPS.', 's2member'); |
| 249 |
} |
| 250 |
else |
| 251 |
{ |
| 252 |
//260216 Note: Avoid gating configuration on a server-side HTTPS "loopback" probe. |
| 253 |
// Many shared hosts/WAFs return false negatives for loopback requests (e.g., HEAD blocked, |
| 254 |
// ModSecurity rules, disabled loopback/outbound HTTP). Reachability is verified separately |
| 255 |
// via the "Test Webhook Endpoint" link and PayPal's webhook simulator. |
| 256 |
} |
| 257 |
|
| 258 |
if(!$ppco_https_ready) |
| 259 |
{ |
| 260 |
echo '<div class="ws-menu-page-notice ws-menu-page-notice-info">'."\n"; |
| 261 |
echo '<p><span class="ws-menu-page-error"><strong>'.esc_html__('PayPal Checkout requires HTTPS (SSL).', 's2member').'</strong></span></p>'."\n"; |
| 262 |
echo '<p><span class="ws-menu-page-error">'.esc_html__('This site does not currently have a working HTTPS endpoint for this domain. PayPal Checkout is disabled here because webhooks cannot be delivered without HTTPS.', 's2member').'</span></p>'."\n"; |
| 263 |
echo '<p><code>'.esc_html($ppco_https_reason).'</code></p>'."\n"; |
| 264 |
echo '</div>'."\n"; |
| 265 |
} |
| 266 |
|
| 267 |
echo '<table class="form-table" style="margin:0;">'."\n"; |
| 268 |
echo '<tbody>'."\n"; |
| 269 |
echo '<tr>'."\n"; |
| 270 |
|
| 271 |
echo '<th style="padding-top:0;">'."\n"; |
| 272 |
echo '<label for="ws-plugin--s2member-paypal-checkout-enable-0">'."\n"; |
| 273 |
echo 'Enable PayPal Checkout (Beta)?'."\n"; |
| 274 |
echo '</label>'."\n"; |
| 275 |
echo '</th>'."\n"; |
| 276 |
|
| 277 |
echo '</tr>'."\n"; |
| 278 |
echo '<tr>'."\n"; |
| 279 |
|
| 280 |
echo '<td>'."\n"; |
| 281 |
echo '<input type="radio" name="ws_plugin__s2member_paypal_checkout_enable" id="ws-plugin--s2member-paypal-checkout-enable-0" value="0" onclick="window.s2mPpcoApplyEnvCues&&window.s2mPpcoApplyEnvCues();"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_enable"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-paypal-checkout-enable-0">No</label> <input type="radio" name="ws_plugin__s2member_paypal_checkout_enable" id="ws-plugin--s2member-paypal-checkout-enable-1" value="1" onclick="window.s2mPpcoApplyEnvCues&&window.s2mPpcoApplyEnvCues();"'.((!$ppco_https_ready) ? ' disabled="disabled"' : '').(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_enable"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-paypal-checkout-enable-1">Yes, enable PayPal Checkout.</label><br />'."\n"; |
| 282 |
echo '<em>Only enable this after you have configured PayPal Checkout credentials below. If disabled, s2Member continues using the existing PayPal Standard and Express Checkout integrations.</em>'."\n"; |
| 283 |
|
| 284 |
if(!$ppco_https_ready) |
| 285 |
echo '<br /><span class="ws-menu-page-error">'.esc_html__('Disabled: PayPal Checkout requires HTTPS (SSL) for webhooks. Fix HTTPS for this domain, then enable PayPal Checkout.', 's2member').'</span>'."\n"; |
| 286 |
echo '</td>'."\n"; |
| 287 |
|
| 288 |
echo '</tr>'."\n"; |
| 289 |
echo '<tr>'."\n"; |
| 290 |
|
| 291 |
echo '<th>'."\n"; |
| 292 |
echo '<label for="ws-plugin--s2member-paypal-checkout-sandbox-0">'."\n"; |
| 293 |
echo 'PayPal Checkout Environment'."\n"; |
| 294 |
echo '</label>'."\n"; |
| 295 |
echo '</th>'."\n"; |
| 296 |
|
| 297 |
echo '</tr>'."\n"; |
| 298 |
echo '<tr>'."\n"; |
| 299 |
|
| 300 |
echo '<td>'."\n"; |
| 301 |
echo '<input type="radio" name="ws_plugin__s2member_paypal_checkout_sandbox" id="ws-plugin--s2member-paypal-checkout-sandbox-0" value="0" onclick="window.s2mPpcoApplyEnvCues && window.s2mPpcoApplyEnvCues(\'click-live\');"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-paypal-checkout-sandbox-0">Live</label> <input type="radio" name="ws_plugin__s2member_paypal_checkout_sandbox" id="ws-plugin--s2member-paypal-checkout-sandbox-1" value="1" onclick="window.s2mPpcoApplyEnvCues && window.s2mPpcoApplyEnvCues(\'click-sandbox\');"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox"]) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-paypal-checkout-sandbox-1">Sandbox</label><br />'."\n"; |
| 302 |
echo '<em>This controls which credentials and webhook ID are used at runtime.</em>'."\n"; |
| 303 |
echo '</td>'."\n"; |
| 304 |
|
| 305 |
echo '</tr>'."\n"; |
| 306 |
echo '</tbody>'."\n"; |
| 307 |
echo '</table>'."\n"; |
| 308 |
|
| 309 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 310 |
|
| 311 |
echo '<style type="text/css">'."\n"; |
| 312 |
echo '/* PayPal Checkout (Beta): environment cues (Live vs Sandbox) */'."\n"; |
| 313 |
echo '.ws-plugin--s2member-paypal-checkout-account-details-section .s2m-ppco-env-wrap{border-radius:8px;}'."\n"; |
| 314 |
echo '.ws-plugin--s2member-paypal-checkout-account-details-section .s2m-ppco-env-live-wrap{margin:0 0 18px 0;}'."\n"; |
| 315 |
echo '.ws-plugin--s2member-paypal-checkout-account-details-section .s2m-ppco-env-sandbox-wrap{background:#fcfeff; margin:0 -12px 18px -12px; padding:12px;}'."\n"; |
| 316 |
echo '.ws-plugin--s2member-paypal-checkout-account-details-section .s2m-ppco-env-inactive{opacity:0.50;}'."\n"; |
| 317 |
echo '/* Prevent long <code> strings from forcing horizontal overflow (e.g., webhook URL). */'."\n"; |
| 318 |
echo '.ws-plugin--s2member-paypal-checkout-account-details-section code{display:inline-block; max-width:100%; margin:0 !important; white-space:normal; overflow-wrap:anywhere; word-break:break-word;}'."\n"; |
| 319 |
echo '/* Keep inputs inside the section from overflowing the container when zoomed. */'."\n"; |
| 320 |
echo '.ws-plugin--s2member-paypal-checkout-account-details-section input[type="text"],'."\n"; |
| 321 |
echo '.ws-plugin--s2member-paypal-checkout-account-details-section input[type="password"]{max-width:100%; box-sizing:border-box;}'."\n"; |
| 322 |
echo '</style>'."\n"; |
| 323 |
|
| 324 |
echo '<script type="text/javascript">'."\n"; |
| 325 |
echo 'window.s2mPpcoApplyEnvCues=function(){'."\n"; |
| 326 |
echo ' var en=document.getElementById(\'ws-plugin--s2member-paypal-checkout-enable-1\');'."\n"; |
| 327 |
echo ' var sb=document.getElementById(\'ws-plugin--s2member-paypal-checkout-sandbox-1\');'."\n"; |
| 328 |
echo ' var live=document.querySelector(\'.ws-plugin--s2member-paypal-checkout-account-details-section .s2m-ppco-env-live-wrap\');'."\n"; |
| 329 |
echo ' var sandbox=document.querySelector(\'.ws-plugin--s2member-paypal-checkout-account-details-section .s2m-ppco-env-sandbox-wrap\');'."\n"; |
| 330 |
echo ' if(!live||!sandbox){return;}'."\n"; |
| 331 |
echo ' var enabled=!!(en&&en.checked);'."\n"; |
| 332 |
echo ' var isSandbox=!!(sb&&sb.checked);'."\n"; |
| 333 |
echo ' live.classList.toggle(\'s2m-ppco-env-inactive\', !enabled||isSandbox);'."\n"; |
| 334 |
echo ' sandbox.classList.toggle(\'s2m-ppco-env-inactive\', !enabled||!isSandbox);'."\n"; |
| 335 |
echo '};'."\n"; |
| 336 |
echo 'window.s2mPpcoApplyEnvCues();'."\n"; |
| 337 |
echo '</script>'."\n"; |
| 338 |
|
| 339 |
$ppco_post_back_url = remove_query_arg(array('s2member_ppco_webhook', 'ppco_webhook_env', 's2member_ppco_creds_test', 'ppco_creds_env', 's2member_ppco_clear_cache', 'ppco_clear_env', '_wpnonce')); |
| 340 |
|
| 341 |
$ppco_webhook_nonce = wp_create_nonce('s2member_ppco_webhook'); |
| 342 |
$ppco_creds_test_nonce = wp_create_nonce('s2member_ppco_creds_test'); |
| 343 |
$ppco_clear_cache_nonce = wp_create_nonce('s2member_ppco_clear_cache'); |
| 344 |
|
| 345 |
echo '<script type="text/javascript">'."\n"; |
| 346 |
echo 'window.s2mPpcoPostBackUrl='.wp_json_encode($ppco_post_back_url).';'."\n"; |
| 347 |
echo 'window.s2mPpcoPostAction=function(action,env,nonce){'."\n"; |
| 348 |
echo ' try{'."\n"; |
| 349 |
echo ' var f=document.createElement("form");'."\n"; |
| 350 |
echo ' f.method="post";'."\n"; |
| 351 |
echo ' f.action=window.s2mPpcoPostBackUrl||window.location.href;'."\n"; |
| 352 |
echo ' var add=function(n,v){var i=document.createElement("input");i.type="hidden";i.name=n;i.value=v;f.appendChild(i);};'."\n"; |
| 353 |
echo ' if(action==="webhook"){add("s2member_ppco_webhook","1");add("ppco_webhook_env",env);}'."\n"; |
| 354 |
echo ' else if(action==="creds_test"){add("s2member_ppco_creds_test","1");add("ppco_creds_env",env);}'."\n"; |
| 355 |
echo ' else if(action==="clear_cache"){add("s2member_ppco_clear_cache","1");add("ppco_clear_env",env);}'."\n"; |
| 356 |
echo ' add("_wpnonce",nonce);'."\n"; |
| 357 |
echo ' document.body.appendChild(f);'."\n"; |
| 358 |
echo ' f.submit();'."\n"; |
| 359 |
echo ' }catch(e){}'."\n"; |
| 360 |
echo ' return false;'."\n"; |
| 361 |
echo '};'."\n"; |
| 362 |
echo '</script>'."\n"; |
| 363 |
|
| 364 |
$ppco_webhook_live_url = add_query_arg(array( |
| 365 |
's2member_ppco_webhook' => '1', |
| 366 |
'ppco_webhook_env' => 'live', |
| 367 |
'_wpnonce' => wp_create_nonce('s2member_ppco_webhook'), |
| 368 |
), remove_query_arg(array('s2member_ppco_webhook', 'ppco_webhook_env', 's2member_ppco_creds_test', 'ppco_creds_env', 's2member_ppco_clear_cache', 'ppco_clear_env', '_wpnonce'))); |
| 369 |
|
| 370 |
$ppco_creds_test_live_url = add_query_arg(array( |
| 371 |
's2member_ppco_creds_test' => '1', |
| 372 |
'ppco_creds_env' => 'live', |
| 373 |
'_wpnonce' => wp_create_nonce('s2member_ppco_creds_test'), |
| 374 |
), remove_query_arg(array('s2member_ppco_creds_test', 'ppco_creds_env', 's2member_ppco_webhook', 'ppco_webhook_env', 's2member_ppco_clear_cache', 'ppco_clear_env', '_wpnonce'))); |
| 375 |
|
| 376 |
$ppco_clear_cache_live_url = add_query_arg(array( |
| 377 |
's2member_ppco_clear_cache' => '1', |
| 378 |
'ppco_clear_env' => 'live', |
| 379 |
'_wpnonce' => wp_create_nonce('s2member_ppco_clear_cache'), |
| 380 |
), remove_query_arg(array('s2member_ppco_clear_cache', 'ppco_clear_env', 's2member_ppco_webhook', 'ppco_webhook_env', 's2member_ppco_creds_test', 'ppco_creds_env', '_wpnonce'))); |
| 381 |
|
| 382 |
$ppco_webhook_test_live_url = add_query_arg(array( |
| 383 |
's2member_paypal_webhook' => '1', |
| 384 |
's2member_paypal_webhook_test' => '1', |
| 385 |
'ppco_webhook_env' => 'live', |
| 386 |
'_wpnonce' => wp_create_nonce('s2member_ppco_webhook_test'), |
| 387 |
), home_url("/", 'https')); |
| 388 |
|
| 389 |
$ppco_webhook_sandbox_url = add_query_arg(array( |
| 390 |
's2member_ppco_webhook' => '1', |
| 391 |
'ppco_webhook_env' => 'sandbox', |
| 392 |
'_wpnonce' => wp_create_nonce('s2member_ppco_webhook'), |
| 393 |
), remove_query_arg(array('s2member_ppco_webhook', 'ppco_webhook_env', 's2member_ppco_creds_test', 'ppco_creds_env', 's2member_ppco_clear_cache', 'ppco_clear_env', '_wpnonce'))); |
| 394 |
|
| 395 |
$ppco_creds_test_sandbox_url = add_query_arg(array( |
| 396 |
's2member_ppco_creds_test' => '1', |
| 397 |
'ppco_creds_env' => 'sandbox', |
| 398 |
'_wpnonce' => wp_create_nonce('s2member_ppco_creds_test'), |
| 399 |
), remove_query_arg(array('s2member_ppco_creds_test', 'ppco_creds_env', 's2member_ppco_webhook', 'ppco_webhook_env', 's2member_ppco_clear_cache', 'ppco_clear_env', '_wpnonce'))); |
| 400 |
|
| 401 |
$ppco_clear_cache_sandbox_url = add_query_arg(array( |
| 402 |
's2member_ppco_clear_cache' => '1', |
| 403 |
'ppco_clear_env' => 'sandbox', |
| 404 |
'_wpnonce' => wp_create_nonce('s2member_ppco_clear_cache'), |
| 405 |
), remove_query_arg(array('s2member_ppco_clear_cache', 'ppco_clear_env', 's2member_ppco_webhook', 'ppco_webhook_env', 's2member_ppco_creds_test', 'ppco_creds_env', '_wpnonce'))); |
| 406 |
|
| 407 |
$ppco_webhook_test_sandbox_url = add_query_arg(array( |
| 408 |
's2member_paypal_webhook' => '1', |
| 409 |
's2member_paypal_webhook_test' => '1', |
| 410 |
'ppco_webhook_env' => 'sandbox', |
| 411 |
'_wpnonce' => wp_create_nonce('s2member_ppco_webhook_test'), |
| 412 |
), home_url("/", 'https')); |
| 413 |
|
| 414 |
$ppco_cache = !empty($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_cache"]) && is_array($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_cache"]) ? $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_cache"] : array(); |
| 415 |
|
| 416 |
$ppco_live_cred_id = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_cred_id('live'); |
| 417 |
$ppco_sandbox_cred_id = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_cred_id('sandbox'); |
| 418 |
|
| 419 |
$ppco_plan_count_live = (!empty($ppco_cache[$ppco_live_cred_id]['live']['plan_ids']) && is_array($ppco_cache[$ppco_live_cred_id]['live']['plan_ids'])) ? count($ppco_cache[$ppco_live_cred_id]['live']['plan_ids']) : 0; |
| 420 |
$ppco_prod_count_live = (!empty($ppco_cache[$ppco_live_cred_id]['live']['product_ids']) && is_array($ppco_cache[$ppco_live_cred_id]['live']['product_ids'])) ? count($ppco_cache[$ppco_live_cred_id]['live']['product_ids']) : 0; |
| 421 |
|
| 422 |
$ppco_plan_count_sandbox = (!empty($ppco_cache[$ppco_sandbox_cred_id]['sandbox']['plan_ids']) && is_array($ppco_cache[$ppco_sandbox_cred_id]['sandbox']['plan_ids'])) ? count($ppco_cache[$ppco_sandbox_cred_id]['sandbox']['plan_ids']) : 0; |
| 423 |
$ppco_prod_count_sandbox = (!empty($ppco_cache[$ppco_sandbox_cred_id]['sandbox']['product_ids']) && is_array($ppco_cache[$ppco_sandbox_cred_id]['sandbox']['product_ids'])) ? count($ppco_cache[$ppco_sandbox_cred_id]['sandbox']['product_ids']) : 0; |
| 424 |
|
| 425 |
echo '<div class="s2m-ppco-env-wrap s2m-ppco-env-live-wrap'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox"]) ? ' s2m-ppco-env-inactive' : '').'">'."\n"; |
| 426 |
echo '<h3 style="margin:0 0 6px 0;">Live</h3>'."\n"; |
| 427 |
|
| 428 |
echo '<table class="form-table">'."\n"; |
| 429 |
echo '<tbody>'."\n"; |
| 430 |
|
| 431 |
echo '<tr>'."\n"; |
| 432 |
echo '<th>'."\n"; |
| 433 |
echo '<label for="ws-plugin--s2member-paypal-checkout-client-id">'."\n"; |
| 434 |
echo 'PayPal Checkout Client ID (Live — REST API):'."\n"; |
| 435 |
echo '</label>'."\n"; |
| 436 |
echo '</th>'."\n"; |
| 437 |
echo '</tr>'."\n"; |
| 438 |
|
| 439 |
echo '<tr>'."\n"; |
| 440 |
echo '<td>'."\n"; |
| 441 |
echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_paypal_checkout_client_id" id="ws-plugin--s2member-paypal-checkout-client-id" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_client_id"]).'" /><br />'."\n"; |
| 442 |
echo 'At PayPal, see: <strong><a href="https://developer.paypal.com/dashboard/applications/live" target="_blank" rel="external">My Apps & Credentials (Live)</a></strong>'."\n"; |
| 443 |
echo '</td>'."\n"; |
| 444 |
echo '</tr>'."\n"; |
| 445 |
|
| 446 |
echo '<tr>'."\n"; |
| 447 |
echo '<th>'."\n"; |
| 448 |
echo '<label for="ws-plugin--s2member-paypal-checkout-client-secret">'."\n"; |
| 449 |
echo 'PayPal Checkout Client Secret (Live — REST API):'."\n"; |
| 450 |
echo '</label>'."\n"; |
| 451 |
echo '</th>'."\n"; |
| 452 |
echo '</tr>'."\n"; |
| 453 |
|
| 454 |
echo '<tr>'."\n"; |
| 455 |
echo '<td>'."\n"; |
| 456 |
echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_paypal_checkout_client_secret" id="ws-plugin--s2member-paypal-checkout-client-secret" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_client_secret"]).'" /><br />'."\n"; |
| 457 |
echo 'At PayPal, see: <strong><a href="https://developer.paypal.com/dashboard/applications/live" target="_blank" rel="external">My Apps & Credentials (Live)</a></strong>'."\n"; |
| 458 |
|
| 459 |
echo '<table class="form-table" style="margin:10px 0 0 0;">'."\n"; |
| 460 |
echo '<tbody>'."\n"; |
| 461 |
echo '<tr>'."\n"; |
| 462 |
echo '<th style="width:260px; padding:0 10px 0 0;">'."\n"; |
| 463 |
if($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_client_id"] && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_client_secret"]) |
| 464 |
echo '<a class="button" style="min-width:240px; text-align:center;" href="'.esc_attr($ppco_creds_test_live_url).'" onclick="return window.s2mPpcoPostAction(\'creds_test\',\'live\',\''.esc_attr($ppco_creds_test_nonce).'\');">'.esc_html__('Test Credentials', 's2member').'</a>'."\n"; |
| 465 |
else echo '<span class="button" style="min-width:240px; text-align:center; opacity:0.50; cursor:default; pointer-events:none;" title="'.esc_attr__('Save Live credentials first.', 's2member').'">'.esc_html__('Test Credentials', 's2member').'</span>'."\n"; |
| 466 |
echo '</th>'."\n"; |
| 467 |
echo '<td style="padding:0;">'."\n"; |
| 468 |
echo '<em>'.esc_html__('Verifies your Live Client ID/Secret by requesting an access token.', 's2member').'</em>'."\n"; |
| 469 |
echo '</td>'."\n"; |
| 470 |
echo '</tr>'."\n"; |
| 471 |
echo '</tbody>'."\n"; |
| 472 |
echo '</table>'."\n"; |
| 473 |
|
| 474 |
echo '</td>'."\n"; |
| 475 |
echo '</tr>'."\n"; |
| 476 |
|
| 477 |
echo '<tr>'."\n"; |
| 478 |
echo '<th>'."\n"; |
| 479 |
echo '<label for="ws-plugin--s2member-paypal-checkout-webhook-id">'."\n"; |
| 480 |
echo 'PayPal Checkout Webhook ID (Live):'."\n"; |
| 481 |
echo '</label>'."\n"; |
| 482 |
echo '</th>'."\n"; |
| 483 |
echo '</tr>'."\n"; |
| 484 |
|
| 485 |
echo '<tr>'."\n"; |
| 486 |
echo '<td>'."\n"; |
| 487 |
echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_paypal_checkout_webhook_id" id="ws-plugin--s2member-paypal-checkout-webhook-id" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_webhook_id"]).'" />'."\n"; |
| 488 |
echo '<br /><em>'.esc_html__('From your PayPal app webhook settings (Live).', 's2member').'</em><br />'."\n"; |
| 489 |
|
| 490 |
echo '<table class="form-table" style="margin:12px 0 0 0;">'."\n"; |
| 491 |
echo '<tbody>'."\n"; |
| 492 |
|
| 493 |
echo '<tr>'."\n"; |
| 494 |
echo '<th style="width:260px; padding:0 10px 0 0;">'."\n"; |
| 495 |
if($ppco_https_ready && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_client_id"] && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_client_secret"]) |
| 496 |
echo '<a class="button button-primary" style="min-width:250px; text-align:center; color:#fff !important;" href="'.esc_attr($ppco_webhook_live_url).'" onclick="return window.s2mPpcoPostAction(\'webhook\',\'live\',\''.esc_attr($ppco_webhook_nonce).'\');">'.esc_html__('Create/Update Webhook', 's2member').'</a>'."\n"; |
| 497 |
else if(!$ppco_https_ready) |
| 498 |
echo '<span class="button button-primary" style="min-width:250px; text-align:center; color:#fff !important; opacity:0.50; cursor:default; pointer-events:none;" title="'.esc_attr__('HTTPS required.', 's2member').'">'.esc_html__('Create/Update Webhook', 's2member').'</span>'."\n"; |
| 499 |
else |
| 500 |
echo '<span class="button button-primary" style="min-width:250px; text-align:center; color:#fff !important; opacity:0.50; cursor:default; pointer-events:none;" title="'.esc_attr__('Save Live credentials first.', 's2member').'">'.esc_html__('Create/Update Webhook', 's2member').'</span>'."\n"; |
| 501 |
echo '</th>'."\n"; |
| 502 |
echo '<td style="padding:0;">'."\n"; |
| 503 |
echo '<em>'.esc_html__('Registers or updates your webhook URL and required events with PayPal (HTTPS required).', 's2member').' '.esc_html__('If your site URL changes, re-run Create/Update Webhook to update the callback URL at PayPal.', 's2member').'</em>'."\n"; |
| 504 |
echo '</td>'."\n"; |
| 505 |
echo '</tr>'."\n"; |
| 506 |
|
| 507 |
echo '<tr>'."\n"; |
| 508 |
echo '<th style="width:260px; padding:8px 10px 0 0;">'."\n"; |
| 509 |
if($ppco_https_ready && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_client_id"] && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_client_secret"] && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_webhook_id"]) |
| 510 |
echo '<a class="button" style="min-width:250px; text-align:center;" target="_blank" href="'.esc_attr($ppco_webhook_test_live_url).'">'.esc_html__('Test Webhook Endpoint', 's2member').'</a>'."\n"; |
| 511 |
else if(!$ppco_https_ready) |
| 512 |
echo '<span class="button disabled" style="min-width:250px; text-align:center;" title="'.esc_attr__('HTTPS required.', 's2member').'">'.esc_html__('Test Webhook Endpoint', 's2member').'</span>'."\n"; |
| 513 |
else if(!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_client_id"] || !$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_client_secret"]) |
| 514 |
echo '<span class="button disabled" style="min-width:250px; text-align:center;" title="'.esc_attr__('Save Live credentials first.', 's2member').'">'.esc_html__('Test Webhook Endpoint', 's2member').'</span>'."\n"; |
| 515 |
else |
| 516 |
echo '<span class="button" style="min-width:250px; text-align:center; opacity:0.50; cursor:default; pointer-events:none;" title="'.esc_attr__('Set a Live Webhook ID first (or use Create/Update Webhook).', 's2member').'">'.esc_html__('Test Webhook Endpoint', 's2member').'</span>'."\n"; |
| 517 |
echo '</th>'."\n"; |
| 518 |
echo '<td style="padding:8px 0 0 0;">'."\n"; |
| 519 |
echo '<em>'.esc_html__('Reachability-only check. Use real webhooks for end-to-end verification.', 's2member').'</em>'."\n"; |
| 520 |
echo '<br /><em>'.esc_html__('Test URL: ', 's2member').'<code>'.esc_html($ppco_webhook_test_live_url).'</code></em>'."\n"; |
| 521 |
echo '</td>'."\n"; |
| 522 |
echo '</tr>'."\n"; |
| 523 |
|
| 524 |
echo '</tbody>'."\n"; |
| 525 |
echo '</table>'."\n"; |
| 526 |
|
| 527 |
echo '<br /><br />'."\n"; |
| 528 |
echo '<em>'.esc_html__('Webhook URL:', 's2member').'</em><br /><code>'.esc_html(add_query_arg("s2member_paypal_webhook", "1", home_url("/", 'https'))).'</code>'."\n"; |
| 529 |
echo '<br /><em class="ws-menu-page-hilite">'.esc_html__('Note: PayPal requires an HTTPS (SSL) webhook URL.', 's2member').'</em>'."\n"; |
| 530 |
|
| 531 |
$ppco_https_scheme = strtolower((string)c_ws_plugin__s2member_utils_urls::parse_url(home_url('/'), PHP_URL_SCHEME)); |
| 532 |
|
| 533 |
//260224 Reverse-proxy/Cloudflare fallback for admin-side HTTPS warning display. |
| 534 |
$ppco_proxy_https = false; |
| 535 |
if(!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && stripos(strtolower((string)$_SERVER['HTTP_X_FORWARDED_PROTO']), 'https') !== false) |
| 536 |
$ppco_proxy_https = true; |
| 537 |
else if(!empty($_SERVER['HTTP_X_FORWARDED_SSL']) && strtolower((string)$_SERVER['HTTP_X_FORWARDED_SSL']) === 'on') |
| 538 |
$ppco_proxy_https = true; |
| 539 |
else if(!empty($_SERVER['HTTPS']) && in_array(strtolower((string)$_SERVER['HTTPS']), array('on', '1'), true)) |
| 540 |
$ppco_proxy_https = true; |
| 541 |
else if(!empty($_SERVER['HTTP_CF_VISITOR']) && stripos((string)$_SERVER['HTTP_CF_VISITOR'], '"scheme":"https"') !== false) |
| 542 |
$ppco_proxy_https = true; |
| 543 |
|
| 544 |
if($ppco_https_scheme !== 'https' && !$ppco_proxy_https) |
| 545 |
echo '<br /><span class="ws-menu-page-error">'.esc_html__('Warning: Your WordPress Site URL/Home URL is currently not configured for HTTPS. PayPal may reject webhook creation and delivery until your site supports SSL and your Site URL uses https://.', 's2member').'</span>'."\n"; |
| 546 |
else |
| 547 |
{ |
| 548 |
$ppco_https_probe = wp_remote_head(home_url("/", 'https'), array('timeout' => 8, 'redirection' => 0)); |
| 549 |
$ppco_https_code = !is_wp_error($ppco_https_probe) ? (int)wp_remote_retrieve_response_code($ppco_https_probe) : 0; |
| 550 |
$ppco_https_loc = !is_wp_error($ppco_https_probe) ? (string)wp_remote_retrieve_header($ppco_https_probe, 'location') : ''; |
| 551 |
|
| 552 |
if(is_wp_error($ppco_https_probe)) |
| 553 |
echo '<br /><span class="ws-menu-page-error">'.esc_html__('Warning: Your HTTPS endpoint could not be reached from this server. This often indicates SSL/TLS or virtual-host configuration issues; PayPal webhooks may not be delivered successfully.', 's2member').'<br /><code>'.esc_html($ppco_https_probe->get_error_message()).'</code></span>'."\n"; |
| 554 |
else if($ppco_https_loc && stripos($ppco_https_loc, 'cgi-sys/defaultwebpage.cgi') !== false) |
| 555 |
echo '<br /><span class="ws-menu-page-error">'.esc_html__('Warning: Your HTTPS endpoint appears to redirect to a hosting default page (cgi-sys/defaultwebpage.cgi). This suggests SSL/virtual-host configuration issues; PayPal webhooks may not be delivered successfully.', 's2member').'</span>'."\n"; |
| 556 |
else if($ppco_https_code && $ppco_https_code >= 400) |
| 557 |
echo '<br /><span class="ws-menu-page-error">'.sprintf(esc_html__('Warning: Server-side probe to your HTTPS endpoint returned HTTP %1$s. This can be caused by SSL/virtual-host configuration issues, but it can also be a false negative due to security rules that block loopback requests. Use the “Test Webhook Endpoint” link and PayPal\'s webhook simulator to confirm external reachability.', 's2member'), (int)$ppco_https_code).'</span>'."\n"; |
| 558 |
} |
| 559 |
|
| 560 |
//260824.1727 Include payment, dispute, and subscription lifecycle events required by Checkout processing. |
| 561 |
echo '<br /><br /><em>'.esc_html__('Required Events:', 's2member').'</em><br /><code>PAYMENT.SALE.COMPLETED</code> <code>PAYMENT.CAPTURE.COMPLETED</code> <code>PAYMENT.SALE.REFUNDED</code> <code>PAYMENT.CAPTURE.REFUNDED</code> <code>PAYMENT.SALE.REVERSED</code> <code>PAYMENT.CAPTURE.REVERSED</code> <code>CUSTOMER.DISPUTE.CREATED</code> <code>BILLING.SUBSCRIPTION.CREATED</code> <code>BILLING.SUBSCRIPTION.ACTIVATED</code> <code>BILLING.SUBSCRIPTION.RE-ACTIVATED</code> <code>BILLING.SUBSCRIPTION.UPDATED</code> <code>BILLING.SUBSCRIPTION.CANCELLED</code> <code>BILLING.SUBSCRIPTION.SUSPENDED</code> <code>BILLING.SUBSCRIPTION.EXPIRED</code> <code>BILLING.SUBSCRIPTION.PAYMENT.FAILED</code>'."\n"; |
| 562 |
|
| 563 |
echo '<p style="margin:10px 0 0 0;"><em>'.esc_html__('Tip: Use PayPal\'s Webhooks Events dashboard to view and re-deliver webhook events while testing.', 's2member').' <a href="https://developer.paypal.com/api/rest/webhooks/events-dashboard/" target="_blank" rel="external">'.esc_html__('Open Events Dashboard', 's2member').'</a></em></p>'."\n"; |
| 564 |
|
| 565 |
if(!$ppco_https_ready) |
| 566 |
echo '<p style="margin:10px 0 0 0;"><span class="ws-menu-page-error">'.esc_html__('Disabled: PayPal webhooks require a working HTTPS (SSL) endpoint on this domain.', 's2member').'</span></p>'."\n"; |
| 567 |
|
| 568 |
echo '<p style="margin:16px 0 10px 0;"><strong>'.esc_html__('Plan/Product Cache (Live)', 's2member').'</strong></p>'."\n"; |
| 569 |
echo '<table class="form-table" style="margin:0;">'."\n"; |
| 570 |
echo '<tbody>'."\n"; |
| 571 |
|
| 572 |
echo '<tr>'."\n"; |
| 573 |
echo '<th style="width:260px; padding:0 10px 0 0;">'."\n"; |
| 574 |
if((int)$ppco_plan_count_live || (int)$ppco_prod_count_live) |
| 575 |
echo '<a class="button" style="min-width:250px; text-align:center;" href="'.esc_attr($ppco_clear_cache_live_url).'" onclick="return window.s2mPpcoPostAction(\'clear_cache\',\'live\',\''.esc_attr($ppco_clear_cache_nonce).'\');">'.esc_html__('Clear Plan/Product Cache', 's2member').'</a>'."\n"; |
| 576 |
else echo '<span class="button disabled" style="min-width:250px; text-align:center;" title="'.esc_attr__('Cache is already empty.', 's2member').'">'.esc_html__('Clear Plan/Product Cache', 's2member').'</span>'."\n"; |
| 577 |
echo '</th>'."\n"; |
| 578 |
echo '<td style="padding:0;">'."\n"; |
| 579 |
echo '<em>'.sprintf(esc_html__('Clears the local PayPal Checkout Product/Plan ID cache (used to avoid creating duplicates). Existing subscriptions are unaffected. Next checkout will create new Products/Plans as needed. Current cache: %1$s plan(s), %2$s product(s).', 's2member'), (int)$ppco_plan_count_live, (int)$ppco_prod_count_live).'</em>'."\n"; |
| 580 |
echo '</td>'."\n"; |
| 581 |
echo '</tr>'."\n"; |
| 582 |
|
| 583 |
echo '</tbody>'."\n"; |
| 584 |
echo '</table>'."\n"; |
| 585 |
|
| 586 |
echo '</td>'."\n"; |
| 587 |
echo '</tr>'."\n"; |
| 588 |
|
| 589 |
echo '</tbody>'."\n"; |
| 590 |
echo '</table>'."\n"; |
| 591 |
echo '</div>'."\n"; |
| 592 |
|
| 593 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 594 |
|
| 595 |
echo '<div class="s2m-ppco-env-wrap s2m-ppco-env-sandbox-wrap'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox"]) ? ' s2m-ppco-env-inactive' : '').'">'."\n"; |
| 596 |
echo '<h3 style="margin:0 0 6px 0;">Sandbox</h3>'."\n"; |
| 597 |
|
| 598 |
echo '<table class="form-table">'."\n"; |
| 599 |
echo '<tbody>'."\n"; |
| 600 |
|
| 601 |
echo '<tr>'."\n"; |
| 602 |
echo '<th>'."\n"; |
| 603 |
echo '<label for="ws-plugin--s2member-paypal-checkout-sandbox-client-id">'."\n"; |
| 604 |
echo 'PayPal Checkout Client ID (Sandbox — REST API):'."\n"; |
| 605 |
echo '</label>'."\n"; |
| 606 |
echo '</th>'."\n"; |
| 607 |
echo '</tr>'."\n"; |
| 608 |
|
| 609 |
echo '<tr>'."\n"; |
| 610 |
echo '<td>'."\n"; |
| 611 |
echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_paypal_checkout_sandbox_client_id" id="ws-plugin--s2member-paypal-checkout-sandbox-client-id" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_client_id"]).'" /><br />'."\n"; |
| 612 |
echo 'At PayPal, see: <strong><a href="https://developer.paypal.com/dashboard/applications/sandbox" target="_blank" rel="external">My Apps & Credentials (Sandbox)</a></strong>'."\n"; |
| 613 |
echo '</td>'."\n"; |
| 614 |
echo '</tr>'."\n"; |
| 615 |
|
| 616 |
echo '<tr>'."\n"; |
| 617 |
echo '<th>'."\n"; |
| 618 |
echo '<label for="ws-plugin--s2member-paypal-checkout-sandbox-client-secret">'."\n"; |
| 619 |
echo 'PayPal Checkout Client Secret (Sandbox — REST API):'."\n"; |
| 620 |
echo '</label>'."\n"; |
| 621 |
echo '</th>'."\n"; |
| 622 |
echo '</tr>'."\n"; |
| 623 |
|
| 624 |
echo '<tr>'."\n"; |
| 625 |
echo '<td>'."\n"; |
| 626 |
echo '<input type="password" autocomplete="off" name="ws_plugin__s2member_paypal_checkout_sandbox_client_secret" id="ws-plugin--s2member-paypal-checkout-sandbox-client-secret" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_client_secret"]).'" /><br />'."\n"; |
| 627 |
echo 'At PayPal, see: <strong><a href="https://developer.paypal.com/dashboard/applications/sandbox" target="_blank" rel="external">My Apps & Credentials (Sandbox)</a></strong>'."\n"; |
| 628 |
|
| 629 |
echo '<table class="form-table" style="margin:10px 0 0 0;">'."\n"; |
| 630 |
echo '<tbody>'."\n"; |
| 631 |
echo '<tr>'."\n"; |
| 632 |
echo '<th style="width:260px; padding:0 10px 0 0;">'."\n"; |
| 633 |
if($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_client_id"] && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_client_secret"]) |
| 634 |
echo '<a class="button" style="min-width:240px; text-align:center;" href="'.esc_attr($ppco_creds_test_sandbox_url).'" onclick="return window.s2mPpcoPostAction(\'creds_test\',\'sandbox\',\''.esc_attr($ppco_creds_test_nonce).'\');">'.esc_html__('Test Credentials', 's2member').'</a>'."\n"; |
| 635 |
else echo '<span class="button" style="min-width:240px; text-align:center; opacity:0.50; cursor:default; pointer-events:none;" title="'.esc_attr__('Save Sandbox credentials first.', 's2member').'">'.esc_html__('Test Credentials', 's2member').'</span>'."\n"; |
| 636 |
echo '</th>'."\n"; |
| 637 |
echo '<td style="padding:0;">'."\n"; |
| 638 |
echo '<em>'.esc_html__('Verifies your Sandbox Client ID/Secret by requesting an access token.', 's2member').'</em>'."\n"; |
| 639 |
echo '</td>'."\n"; |
| 640 |
echo '</tr>'."\n"; |
| 641 |
echo '</tbody>'."\n"; |
| 642 |
echo '</table>'."\n"; |
| 643 |
|
| 644 |
echo '</td>'."\n"; |
| 645 |
echo '</tr>'."\n"; |
| 646 |
|
| 647 |
echo '<tr>'."\n"; |
| 648 |
echo '<th>'."\n"; |
| 649 |
echo '<label for="ws-plugin--s2member-paypal-checkout-sandbox-webhook-id">'."\n"; |
| 650 |
echo 'PayPal Checkout Webhook ID (Sandbox):'."\n"; |
| 651 |
echo '</label>'."\n"; |
| 652 |
echo '</th>'."\n"; |
| 653 |
echo '</tr>'."\n"; |
| 654 |
|
| 655 |
echo '<tr>'."\n"; |
| 656 |
echo '<td>'."\n"; |
| 657 |
echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_paypal_checkout_sandbox_webhook_id" id="ws-plugin--s2member-paypal-checkout-sandbox-webhook-id" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_webhook_id"]).'" />'."\n"; |
| 658 |
echo '<br /><em>'.esc_html__('From your PayPal app webhook settings (Sandbox).', 's2member').'</em><br />'."\n"; |
| 659 |
|
| 660 |
echo '<table class="form-table" style="margin:12px 0 0 0;">'."\n"; |
| 661 |
echo '<tbody>'."\n"; |
| 662 |
|
| 663 |
echo '<tr>'."\n"; |
| 664 |
echo '<th style="width:260px; padding:0 10px 0 0;">'."\n"; |
| 665 |
if($ppco_https_ready && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_client_id"] && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_client_secret"]) |
| 666 |
echo '<a class="button button-primary" style="min-width:250px; text-align:center; color:#fff !important;" href="'.esc_attr($ppco_webhook_sandbox_url).'" onclick="return window.s2mPpcoPostAction(\'webhook\',\'sandbox\',\''.esc_attr($ppco_webhook_nonce).'\');">'.esc_html__('Create/Update Webhook', 's2member').'</a>'."\n"; |
| 667 |
else if(!$ppco_https_ready) |
| 668 |
echo '<span class="button button-primary" style="min-width:250px; text-align:center; color:#fff !important; opacity:0.50; cursor:default; pointer-events:none;" title="'.esc_attr__('HTTPS required.', 's2member').'">'.esc_html__('Create/Update Webhook', 's2member').'</span>'."\n"; |
| 669 |
else |
| 670 |
echo '<span class="button button-primary" style="min-width:250px; text-align:center; color:#fff !important; opacity:0.50; cursor:default; pointer-events:none;" title="'.esc_attr__('Save Sandbox credentials first.', 's2member').'">'.esc_html__('Create/Update Webhook', 's2member').'</span>'."\n"; |
| 671 |
echo '</th>'."\n"; |
| 672 |
echo '<td style="padding:0;">'."\n"; |
| 673 |
echo '<em>'.esc_html__('Registers or updates your webhook URL and required events with PayPal (HTTPS required).', 's2member').' '.esc_html__('If your site URL changes, re-run Create/Update Webhook to update the callback URL at PayPal.', 's2member').'</em>'."\n"; |
| 674 |
echo '</td>'."\n"; |
| 675 |
echo '</tr>'."\n"; |
| 676 |
|
| 677 |
echo '<tr>'."\n"; |
| 678 |
echo '<th style="width:260px; padding:8px 10px 0 0;">'."\n"; |
| 679 |
if($ppco_https_ready && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_client_id"] && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_client_secret"] && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_webhook_id"]) |
| 680 |
echo '<a class="button" style="min-width:250px; text-align:center;" target="_blank" href="'.esc_attr($ppco_webhook_test_sandbox_url).'">'.esc_html__('Test Webhook Endpoint', 's2member').'</a>'."\n"; |
| 681 |
else if(!$ppco_https_ready) |
| 682 |
echo '<span class="button" style="min-width:250px; text-align:center; opacity:0.50; cursor:default; pointer-events:none;" title="'.esc_attr__('HTTPS required.', 's2member').'">'.esc_html__('Test Webhook Endpoint', 's2member').'</span>'."\n"; |
| 683 |
else if(!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_client_id"] || !$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_checkout_sandbox_client_secret"]) |
| 684 |
echo '<span class="button" style="min-width:250px; text-align:center; opacity:0.50; cursor:default; pointer-events:none;" title="'.esc_attr__('Save Sandbox credentials first.', 's2member').'">'.esc_html__('Test Webhook Endpoint', 's2member').'</span>'."\n"; |
| 685 |
else |
| 686 |
echo '<span class="button" style="min-width:250px; text-align:center; opacity:0.50; cursor:default; pointer-events:none;" title="'.esc_attr__('Set a Sandbox Webhook ID first (or use Create/Update Webhook).', 's2member').'">'.esc_html__('Test Webhook Endpoint', 's2member').'</span>'."\n"; |
| 687 |
echo '</th>'."\n"; |
| 688 |
echo '<td style="padding:8px 0 0 0;">'."\n"; |
| 689 |
echo '<em>'.esc_html__('Reachability-only check. Use real webhooks for end-to-end verification.', 's2member').'</em>'."\n"; |
| 690 |
echo '<br /><em>'.esc_html__('Test URL: ', 's2member').'<code>'.esc_html($ppco_webhook_test_sandbox_url).'</code></em>'."\n"; |
| 691 |
echo '</td>'."\n"; |
| 692 |
echo '</tr>'."\n"; |
| 693 |
|
| 694 |
echo '</tbody>'."\n"; |
| 695 |
echo '</table>'."\n"; |
| 696 |
|
| 697 |
echo '<br /><br />'."\n"; |
| 698 |
echo '<em>'.esc_html__('Webhook URL:', 's2member').'</em><br /><code>'.esc_html(add_query_arg("s2member_paypal_webhook", "1", home_url("/", 'https'))).'</code>'."\n"; |
| 699 |
echo '<br /><em class="ws-menu-page-hilite">'.esc_html__('Note: PayPal requires an HTTPS (SSL) webhook URL.', 's2member').'</em>'."\n"; |
| 700 |
|
| 701 |
//260824.1727 Include payment, dispute, and subscription lifecycle events required by Checkout processing. |
| 702 |
echo '<br /><br /><em>'.esc_html__('Required Events:', 's2member').'</em><br /><code>PAYMENT.SALE.COMPLETED</code> <code>PAYMENT.CAPTURE.COMPLETED</code> <code>PAYMENT.SALE.REFUNDED</code> <code>PAYMENT.CAPTURE.REFUNDED</code> <code>PAYMENT.SALE.REVERSED</code> <code>PAYMENT.CAPTURE.REVERSED</code> <code>CUSTOMER.DISPUTE.CREATED</code> <code>BILLING.SUBSCRIPTION.CREATED</code> <code>BILLING.SUBSCRIPTION.ACTIVATED</code> <code>BILLING.SUBSCRIPTION.RE-ACTIVATED</code> <code>BILLING.SUBSCRIPTION.UPDATED</code> <code>BILLING.SUBSCRIPTION.CANCELLED</code> <code>BILLING.SUBSCRIPTION.SUSPENDED</code> <code>BILLING.SUBSCRIPTION.EXPIRED</code> <code>BILLING.SUBSCRIPTION.PAYMENT.FAILED</code>'."\n"; |
| 703 |
|
| 704 |
echo '<p style="margin:10px 0 0 0;"><em>'.esc_html__('Tip: Use PayPal\'s Webhooks Events dashboard to view and re-deliver webhook events while testing.', 's2member').' <a href="https://developer.paypal.com/api/rest/webhooks/events-dashboard/" target="_blank" rel="external">'.esc_html__('Open Events Dashboard', 's2member').'</a></em></p>'."\n"; |
| 705 |
|
| 706 |
if(!$ppco_https_ready) |
| 707 |
echo '<p style="margin:10px 0 0 0;"><span class="ws-menu-page-error">'.esc_html__('Disabled: PayPal webhooks require a working HTTPS (SSL) endpoint on this domain.', 's2member').'</span></p>'."\n"; |
| 708 |
|
| 709 |
echo '<p style="margin:16px 0 10px 0;"><strong>'.esc_html__('Plan/Product Cache (Sandbox)', 's2member').'</strong></p>'."\n"; |
| 710 |
echo '<table class="form-table" style="margin:0;">'."\n"; |
| 711 |
echo '<tbody>'."\n"; |
| 712 |
|
| 713 |
echo '<tr>'."\n"; |
| 714 |
echo '<th style="width:260px; padding:0 10px 0 0;">'."\n"; |
| 715 |
if((int)$ppco_plan_count_sandbox || (int)$ppco_prod_count_sandbox) |
| 716 |
echo '<a class="button" style="min-width:250px; text-align:center;" href="'.esc_attr($ppco_clear_cache_sandbox_url).'" onclick="return window.s2mPpcoPostAction(\'clear_cache\',\'sandbox\',\''.esc_attr($ppco_clear_cache_nonce).'\');">'.esc_html__('Clear Plan/Product Cache', 's2member').'</a>'."\n"; |
| 717 |
else echo '<span class="button" style="min-width:250px; text-align:center; opacity:0.50; cursor:default; pointer-events:none;" title="'.esc_attr__('Cache is already empty.', 's2member').'">'.esc_html__('Clear Plan/Product Cache', 's2member').'</span>'."\n"; |
| 718 |
echo '</th>'."\n"; |
| 719 |
echo '<td style="padding:0;">'."\n"; |
| 720 |
echo '<em>'.sprintf(esc_html__('Clears the local PayPal Checkout Product/Plan ID cache (used to avoid creating duplicates). Existing subscriptions are unaffected. Next checkout will create new Products/Plans as needed. Current cache: %1$s plan(s), %2$s product(s).', 's2member'), (int)$ppco_plan_count_sandbox, (int)$ppco_prod_count_sandbox).'</em>'."\n"; |
| 721 |
echo '</td>'."\n"; |
| 722 |
echo '</tr>'."\n"; |
| 723 |
|
| 724 |
echo '</tbody>'."\n"; |
| 725 |
echo '</table>'."\n"; |
| 726 |
|
| 727 |
echo '</td>'."\n"; |
| 728 |
echo '</tr>'."\n"; |
| 729 |
|
| 730 |
echo '</tbody>'."\n"; |
| 731 |
echo '</table>'."\n"; |
| 732 |
echo '</div>'."\n"; |
| 733 |
|
| 734 |
echo '</div>'."\n"; // .ws-menu-page-section |
| 735 |
|
| 736 |
echo '</div>'."\n"; // .ws-menu-page-group |
| 737 |
|
| 738 |
echo '<div class="ws-menu-page-group" title="PayPal Account Details">'."\n"; |
| 739 |
|
| 740 |
echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-account-details-section">'."\n"; |
| 741 |
echo '<a href="https://s2member.com/r/paypal/" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/src/images/paypal-logo.png" class="ws-menu-page-right" style="width:125px; height:125px; border:0;" alt="." /></a>'."\n"; |
| 742 |
echo '<h3>PayPal Account Details (required, if using PayPal)</h3>'."\n"; |
| 743 |
echo '<p>s2Member integrates with <a href="https://s2member.com/r/paypal/" target="_blank" rel="external">PayPal 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://s2member.com/r/paypal-business-upgrade/" target="_blank" rel="external">upgraded</a> from a Personal account to a Business account by clicking the "Profile" link under your "My Account" tab, selecting "Personal Business Information", and then clicking the "Upgrade Your Account" button. <strong>See also:</strong> This KB article: <a href="http://s2member.com/kb-article/supported-paypal-account-types/" target="_blank" rel="external">PayPal Compatibility (Account Types)</a>.</p>'."\n"; |
| 744 |
echo '<p><em><strong>PayPal API Credentials:</strong> Once you have a PayPal Business account, you\'ll need access to your <a href="http://s2member.com/r/paypal-profile-api-access/" target="_blank" rel="external">PayPal API Credentials</a>. Log into your PayPal account, and navigate to <strong>Profile → API Access (or → Request API Credentials)</strong>. From the available options, please choose "Request API Signature".</em></p>'."\n"; |
| 745 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_account_details", get_defined_vars()); |
| 746 |
|
| 747 |
echo '<table class="form-table">'."\n"; |
| 748 |
echo '<tbody>'."\n"; |
| 749 |
echo '<tr>'."\n"; |
| 750 |
|
| 751 |
echo '<th>'."\n"; |
| 752 |
echo '<label for="ws-plugin--s2member-paypal-merchant-id">'."\n"; |
| 753 |
echo 'Your PayPal Merchant ID:'."\n"; |
| 754 |
echo '</label>'."\n"; |
| 755 |
echo '</th>'."\n"; |
| 756 |
|
| 757 |
echo '</tr>'."\n"; |
| 758 |
echo '<tr>'."\n"; |
| 759 |
|
| 760 |
echo '<td>'."\n"; |
| 761 |
echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_paypal_merchant_id" id="ws-plugin--s2member-paypal-merchant-id" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_merchant_id"]).'" /><br />'."\n"; |
| 762 |
echo 'At PayPal, see: <strong><a href="https://www.paypal.com/businessmanage/account/aboutBusiness" target="_blank" rel="external">Account Settings → Business Information → PayPal Merchant ID</a></strong>'."\n"; |
| 763 |
echo '</td>'."\n"; |
| 764 |
|
| 765 |
echo '</tr>'."\n"; |
| 766 |
echo '<tr>'."\n"; |
| 767 |
|
| 768 |
echo '<th>'."\n"; |
| 769 |
echo '<label for="ws-plugin--s2member-paypal-business">'."\n"; |
| 770 |
echo 'Your PayPal EMail Address:'."\n"; |
| 771 |
echo '</label>'."\n"; |
| 772 |
echo '</th>'."\n"; |
| 773 |
|
| 774 |
echo '</tr>'."\n"; |
| 775 |
echo '<tr>'."\n"; |
| 776 |
|
| 777 |
echo '<td>'."\n"; |
| 778 |
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"; |
| 779 |
echo 'At PayPal, see: <strong><a href="https://www.paypal.com/businessmanage/account/accountOwner" target="_blank" rel="external">Account Settings → Account Owner Information → Email Address</a></strong>'."\n"; |
| 780 |
echo '</td>'."\n"; |
| 781 |
|
| 782 |
echo '</tr>'."\n"; |
| 783 |
echo '</tbody>'."\n"; |
| 784 |
echo '</table>'."\n"; |
| 785 |
|
| 786 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 787 |
|
| 788 |
echo '<table class="form-table">'."\n"; |
| 789 |
echo '<tbody>'."\n"; |
| 790 |
echo '<tr>'."\n"; |
| 791 |
|
| 792 |
echo '<th>'."\n"; |
| 793 |
echo '<label for="ws-plugin--s2member-paypal-api-username">'."\n"; |
| 794 |
echo 'Your PayPal API Username:'."\n"; |
| 795 |
echo '</label>'."\n"; |
| 796 |
echo '</th>'."\n"; |
| 797 |
|
| 798 |
echo '</tr>'."\n"; |
| 799 |
echo '<tr>'."\n"; |
| 800 |
|
| 801 |
echo '<td>'."\n"; |
| 802 |
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"; |
| 803 |
echo 'At PayPal, see: <strong><a href="https://www.paypal.com/businessprofile/mytools/apiaccess/firstparty/signature" target="_blank" rel="external">Account Settings → Website Payments → API Access → NVP/SOAP API integration (Classic) → Manage API Credentials</a></strong>'."\n"; |
| 804 |
echo '</td>'."\n"; |
| 805 |
|
| 806 |
echo '</tr>'."\n"; |
| 807 |
echo '<tr>'."\n"; |
| 808 |
|
| 809 |
echo '<th>'."\n"; |
| 810 |
echo '<label for="ws-plugin--s2member-paypal-api-password">'."\n"; |
| 811 |
echo 'Your PayPal API Password:'."\n"; |
| 812 |
echo '</label>'."\n"; |
| 813 |
echo '</th>'."\n"; |
| 814 |
|
| 815 |
echo '</tr>'."\n"; |
| 816 |
echo '<tr>'."\n"; |
| 817 |
|
| 818 |
echo '<td>'."\n"; |
| 819 |
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"; |
| 820 |
echo 'At PayPal, see: <strong><a href="https://www.paypal.com/businessprofile/mytools/apiaccess/firstparty/signature" target="_blank" rel="external">Account Settings → Website Payments → API Access → NVP/SOAP API integration (Classic) → Manage API Credentials</a></strong>'."\n"; |
| 821 |
echo '</td>'."\n"; |
| 822 |
|
| 823 |
echo '</tr>'."\n"; |
| 824 |
echo '<tr>'."\n"; |
| 825 |
|
| 826 |
echo '<th>'."\n"; |
| 827 |
echo '<label for="ws-plugin--s2member-paypal-api-signature">'."\n"; |
| 828 |
echo 'Your PayPal API Signature:'."\n"; |
| 829 |
echo '</label>'."\n"; |
| 830 |
echo '</th>'."\n"; |
| 831 |
|
| 832 |
echo '</tr>'."\n"; |
| 833 |
echo '<tr>'."\n"; |
| 834 |
|
| 835 |
echo '<td>'."\n"; |
| 836 |
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"; |
| 837 |
echo 'At PayPal, see: <strong><a href="https://www.paypal.com/businessprofile/mytools/apiaccess/firstparty/signature" target="_blank" rel="external">Account Settings → Website Payments → API Access → NVP/SOAP API integration (Classic) → Manage API Credentials</a></strong>'."\n"; |
| 838 |
echo '</td>'."\n"; |
| 839 |
|
| 840 |
echo '</tr>'."\n"; |
| 841 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_account_detail_rows", get_defined_vars()); |
| 842 |
|
| 843 |
echo '</tbody>'."\n"; |
| 844 |
echo '</table>'."\n"; |
| 845 |
|
| 846 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 847 |
|
| 848 |
echo '<table class="form-table" style="margin:0;">'."\n"; |
| 849 |
echo '<tbody>'."\n"; |
| 850 |
echo '<tr>'."\n"; |
| 851 |
|
| 852 |
echo '<th style="padding-top:0;">'."\n"; |
| 853 |
echo '<label for="ws-plugin--s2member-paypal-sandbox">'."\n"; |
| 854 |
echo 'Developer/Sandbox Testing?'."\n"; |
| 855 |
echo '</label>'."\n"; |
| 856 |
echo '</th>'."\n"; |
| 857 |
|
| 858 |
echo '</tr>'."\n"; |
| 859 |
echo '<tr>'."\n"; |
| 860 |
|
| 861 |
echo '<td>'."\n"; |
| 862 |
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> <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"; |
| 863 |
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. See: <a href="http://s2member.com/r/paypal-developers/" target="_blank" rel="external">PayPal Developers</a></em><br />'."\n"; |
| 864 |
echo '<em><strong>Warning:</strong> The PayPal Sandbox doesn\'t always give you an accurate view of what will happen once you go live, and in fact it is sometimes buggy at best. For this reason, our strong recommendation is that instead of using Sandbox Mode to run tests, that you go live and run tests with low-dollar amounts; i.e., $0.01 transactions are possible with PayPal in live mode, and that is a better way to test your installation of s2Member.</em>'."\n"; |
| 865 |
echo '</td>'."\n"; |
| 866 |
|
| 867 |
echo '</tr>'."\n"; |
| 868 |
echo '<tr>'."\n"; |
| 869 |
|
| 870 |
echo '<th>'."\n"; |
| 871 |
echo '<label for="ws-plugin--s2member-paypal-btn-encryption">'."\n"; |
| 872 |
echo 'Button Encryption'."\n"; |
| 873 |
echo '</label>'."\n"; |
| 874 |
echo '</th>'."\n"; |
| 875 |
|
| 876 |
echo '</tr>'."\n"; |
| 877 |
echo '<tr>'."\n"; |
| 878 |
|
| 879 |
echo '<td>'."\n"; |
| 880 |
echo '<p style="margin-bottom: 0.5em;"><span class="ws-menu-page-error">⚠️ PayPal has given some trouble recently with encrypted buttons, so for the time being it\'s recommended to leave it disabled and allow non-encrypted payments. <a href="https://www.paypal.com/businessmanage/preferences/website" target="_blank" rel="external" style="font-style: italic;">PayPal Account Settings → Website Payments → Website Preferences → Encrypted Website Payments</a></span></p>'."\n"; //230807 |
| 881 |
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> <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"; |
| 882 |
echo '<em>If enabled, all of your PayPal Button Shortcodes will produce <em>encrypted</em> PayPal Buttons. This improves security against fraudulent transactions. For extra security, you should update your PayPal account too, under: <strong><a href="https://www.paypal.com/businessmanage/preferences/website" target="_blank" rel="external">Account Settings → Website Payments → Website Preferences → Encrypted Website Payments</a></strong>. 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"; |
| 883 |
echo '</td>'."\n"; |
| 884 |
|
| 885 |
echo '</tr>'."\n"; |
| 886 |
|
| 887 |
if(!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) |
| 888 |
{ |
| 889 |
echo '<tr>'."\n"; |
| 890 |
|
| 891 |
echo '<th>'."\n"; |
| 892 |
echo '<label for="ws-plugin--s2member-gateway-debug-logs">'."\n"; |
| 893 |
echo 'Enable Logging Routines?'."\n"; |
| 894 |
echo '</label>'."\n"; |
| 895 |
echo '</th>'."\n"; |
| 896 |
|
| 897 |
echo '</tr>'."\n"; |
| 898 |
echo '<tr>'."\n"; |
| 899 |
|
| 900 |
echo '<td>'."\n"; |
| 901 |
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> <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 & Return Page logging.</label><br />'."\n"; |
| 902 |
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"; |
| 903 |
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"; |
| 904 |
echo '</td>'."\n"; |
| 905 |
|
| 906 |
echo '</tr>'."\n"; |
| 907 |
echo '<tr>'."\n"; |
| 908 |
|
| 909 |
echo '<td>'."\n"; |
| 910 |
echo '<div class="info" style="margin-bottom:0;">'."\n"; |
| 911 |
echo '<p style="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 payment processing. See: <a href="'.esc_attr(admin_url("/admin.php?page=ws-plugin--s2member-logs")).'">Log Files (Debug)</a>.</span></p>'."\n"; |
| 912 |
echo '<p style="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"; |
| 913 |
echo '</div>'."\n"; |
| 914 |
echo '</td>'."\n"; |
| 915 |
|
| 916 |
echo '</tr>'."\n"; |
| 917 |
} |
| 918 |
echo '</tbody>'."\n"; |
| 919 |
echo '</table>'."\n"; |
| 920 |
|
| 921 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 922 |
|
| 923 |
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"; |
| 924 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_account_details_after_sandbox_tip", get_defined_vars()); |
| 925 |
echo '</div>'."\n"; |
| 926 |
|
| 927 |
echo '</div>'."\n"; |
| 928 |
|
| 929 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_after_paypal_account_details", get_defined_vars()); |
| 930 |
} |
| 931 |
|
| 932 |
if(apply_filters("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_display_paypal_payflow_account_details", c_ws_plugin__s2member_utils_conds::pro_is_installed(), get_defined_vars())) |
| 933 |
{ |
| 934 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_paypal_payflow_account_details", get_defined_vars()); |
| 935 |
|
| 936 |
echo '<div class="ws-menu-page-group" title="PayPal Pro Payflow Edition API Credentials">'."\n"; |
| 937 |
|
| 938 |
echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-payflow-account-details-section">'."\n"; |
| 939 |
echo '<a href="https://s2member.com/r/paypal/" target="_blank"><img src="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"]).'/src/images/paypal-logo.png" class="ws-menu-page-right" style="width:125px; height:125px; border:0;" alt="." /></a>'."\n"; |
| 940 |
echo '<h3>Payflow Account Details (required, if using Payflow)</h3>'."\n"; |
| 941 |
echo '<p>Newer PayPal Pro accounts (i.e., PayPal Pro w/ Payflow Edition), 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 below, will automatically put 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 Edition API instead of the older PayPal Pro DPRP service; which is being slowly phased out in favor of Payflow Edition APIs.</p>'."\n"; |
| 942 |
echo '<p><em><strong>Payflow API Credentials:</strong> Once you have a PayPal Pro account, you\'ll need access to your <a href="http://s2member.com/r/paypal-profile-api-access/" target="_blank" rel="external">Payflow API Credentials</a>. Log into your PayPal account, and navigate to <strong>Profile → API Access (or → Request API Credentials)</strong>. From the available options, please choose "Payflow / API Access". You will need the following credentials: Username, Password, Partner, and Vendor.</em></p>'."\n"; |
| 943 |
echo '<p><em><strong>Important Note:</strong> Supplying Payflow API Credentials here does not mean you can bypass other areas of s2Member\'s configuration; i.e., please supply s2Member with all of your PayPal account details. Your PayPal Pro (Payflow Edition) account is configured here, but up above you will need to configure other Account Details also.</em></p>'."\n"; |
| 944 |
echo '<p><strong>See also:</strong> This KB article: <a href="http://s2member.com/kb-article/supported-paypal-account-types/" target="_blank" rel="external">PayPal Account Types</a>.</p>'."\n"; |
| 945 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_payflow_account_details", get_defined_vars()); |
| 946 |
|
| 947 |
echo '<table class="form-table">'."\n"; |
| 948 |
echo '<tbody>'."\n"; |
| 949 |
echo '<tr>'."\n"; |
| 950 |
|
| 951 |
echo '<th>'."\n"; |
| 952 |
echo '<label for="ws-plugin--s2member-paypal-payflow-api-username">'."\n"; |
| 953 |
echo 'Your Payflow API Username:'."\n"; |
| 954 |
echo '</label>'."\n"; |
| 955 |
echo '</th>'."\n"; |
| 956 |
|
| 957 |
echo '</tr>'."\n"; |
| 958 |
echo '<tr>'."\n"; |
| 959 |
|
| 960 |
echo '<td>'."\n"; |
| 961 |
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"; |
| 962 |
echo 'At PayPal, see: <strong>Profile → API Access (or → Request API Credentials) → Payflow API Access</strong>'."\n"; |
| 963 |
echo '</td>'."\n"; |
| 964 |
|
| 965 |
echo '</tr>'."\n"; |
| 966 |
echo '<tr>'."\n"; |
| 967 |
|
| 968 |
echo '<th>'."\n"; |
| 969 |
echo '<label for="ws-plugin--s2member-paypal-payflow-api-password">'."\n"; |
| 970 |
echo 'Your Payflow API Password:'."\n"; |
| 971 |
echo '</label>'."\n"; |
| 972 |
echo '</th>'."\n"; |
| 973 |
|
| 974 |
echo '</tr>'."\n"; |
| 975 |
echo '<tr>'."\n"; |
| 976 |
|
| 977 |
echo '<td>'."\n"; |
| 978 |
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"; |
| 979 |
echo 'At PayPal, see: <strong>Profile → API Access (or → Request API Credentials) → Payflow API Access</strong>'."\n"; |
| 980 |
echo '</td>'."\n"; |
| 981 |
|
| 982 |
echo '</tr>'."\n"; |
| 983 |
echo '<tr>'."\n"; |
| 984 |
|
| 985 |
echo '<th>'."\n"; |
| 986 |
echo '<label for="ws-plugin--s2member-paypal-payflow-api-partner">'."\n"; |
| 987 |
echo 'Your Payflow API Partner:'."\n"; |
| 988 |
echo '</label>'."\n"; |
| 989 |
echo '</th>'."\n"; |
| 990 |
|
| 991 |
echo '</tr>'."\n"; |
| 992 |
echo '<tr>'."\n"; |
| 993 |
|
| 994 |
echo '<td>'."\n"; |
| 995 |
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"; |
| 996 |
echo 'At PayPal, see: <strong>Profile → API Access (or → Request API Credentials) → Payflow API Access</strong>'."\n"; |
| 997 |
echo '</td>'."\n"; |
| 998 |
|
| 999 |
echo '</tr>'."\n"; |
| 1000 |
echo '<tr>'."\n"; |
| 1001 |
|
| 1002 |
echo '<th>'."\n"; |
| 1003 |
echo '<label for="ws-plugin--s2member-paypal-payflow-api-vendor">'."\n"; |
| 1004 |
echo 'Your Payflow API Vendor:'."\n"; |
| 1005 |
echo '</label>'."\n"; |
| 1006 |
echo '</th>'."\n"; |
| 1007 |
|
| 1008 |
echo '</tr>'."\n"; |
| 1009 |
echo '<tr>'."\n"; |
| 1010 |
|
| 1011 |
echo '<td>'."\n"; |
| 1012 |
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"; |
| 1013 |
echo 'At PayPal, see: <strong>Profile → API Access (or → Request API Credentials) → Payflow API Access</strong>'."\n"; |
| 1014 |
echo '</td>'."\n"; |
| 1015 |
|
| 1016 |
echo '</tr>'."\n"; |
| 1017 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_payflow_account_detail_rows", get_defined_vars()); |
| 1018 |
echo '</tbody>'."\n"; |
| 1019 |
echo '</table>'."\n"; |
| 1020 |
echo '</div>'."\n"; |
| 1021 |
|
| 1022 |
echo '</div>'."\n"; |
| 1023 |
|
| 1024 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_after_paypal_payflow_account_details", get_defined_vars()); |
| 1025 |
} |
| 1026 |
|
| 1027 |
if(apply_filters("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_display_paypal_ipn", TRUE, get_defined_vars())) |
| 1028 |
{ |
| 1029 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_paypal_ipn", get_defined_vars()); |
| 1030 |
|
| 1031 |
echo '<div class="ws-menu-page-group" title="PayPal IPN Integration">'."\n"; |
| 1032 |
|
| 1033 |
echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-ipn-section">'."\n"; |
| 1034 |
echo '<h3>PayPal IPN / Instant Payment Notifications (required, please enable)</h3>'."\n"; |
| 1035 |
echo '<p>Log into your PayPal account and navigate to this section:<br /><strong><a href="http://s2member.com/r/paypal-com-ipn-configuration-page/" target="_blank" rel="external">Account Settings → Website Payments → Instant Payment Notifications</a></strong></p>'."\n"; |
| 1036 |
echo '<p>Edit your IPN settings & turn IPN Notifications: <strong><code>On</code></strong></p>'."\n"; |
| 1037 |
echo '<p>You\'ll need your IPN URL, which is:<br /><code>'.esc_html(home_url("/?s2member_paypal_notify=1", "https")).'</code></p>'."\n"; |
| 1038 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_ipn", get_defined_vars()); |
| 1039 |
|
| 1040 |
echo '<h4 style="margin-bottom:0;"><strong class="ws-menu-page-hilite">Note: SSL is required by PayPal</strong></h4>'."\n"; |
| 1041 |
echo '<p style="margin-top:0;">If you configure your PayPal.com account using the URL above, your site <strong><em>must</em> support SSL</strong> (i.e., the <code>https://</code> protocol). In other words, PayPal\'s system will refuse to accept any URL that does not begin with <code>https://</code>. The IPN URL that s2Member provides (see above) <em>does</em> start with <code>https://</code>. However, that doesn\'t necessarily mean that the URL actually works. Please be sure that your hosting account is configured with a valid SSL certificate before giving this URL to PayPal.</p>'."\n"; |
| 1042 |
|
| 1043 |
//250426 Fallback for IPN Signup Vars. |
| 1044 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 1045 |
|
| 1046 |
echo '<table class="form-table">'."\n"; |
| 1047 |
echo '<tbody>'."\n"; |
| 1048 |
echo '<tr>'."\n"; |
| 1049 |
|
| 1050 |
echo '<th>'."\n"; |
| 1051 |
echo '<label for="ws-plugin--s2member-ipn-signup-vars-fallback">'."\n"; |
| 1052 |
echo 'Enable Fallback for Missing User "IPN Signup Vars"? (beta)<br />'."\n"; |
| 1053 |
echo '<small><em class="ws-menu-page-hilite">* This setting applies to all gateways. [ <a href="#" onclick="alert(\'This configuration option may also appear under the other gateways. You can change it here, but remember that this setting is shared among all Payment Gateways integrated with s2Member.\'); return false;">?</a> ]</em></small>'."\n"; |
| 1054 |
echo '</label>'."\n"; |
| 1055 |
echo '</th>'."\n"; |
| 1056 |
|
| 1057 |
echo '</tr>'."\n"; |
| 1058 |
echo '<tr>'."\n"; |
| 1059 |
|
| 1060 |
echo '<td>'."\n"; |
| 1061 |
echo '<input type="radio" name="ws_plugin__s2member_ipn_signup_vars_fallback" id="ws-plugin--s2member-ipn-signup-vars-fallback-0" value="0"'.((!$GLOBALS['WS_PLUGIN__']['s2member']['o']['ipn_signup_vars_fallback']) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-ipn-signup-vars-fallback-0">No</label> <input type="radio" name="ws_plugin__s2member_ipn_signup_vars_fallback" id="ws-plugin--s2member-ipn-signup-vars-fallback-1" value="1"'.(($GLOBALS['WS_PLUGIN__']['s2member']['o']['ipn_signup_vars_fallback']) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-ipn-signup-vars-fallback-1">Yes, enable user IPN Signup Vars fallback.</label><br />'."\n"; |
| 1062 |
echo '<em>Enable fallback behavior when the user\'s IPN Signup Variables are missing during the IPN event processing (useful for migrated or imported subscriptions, for example).</em><br />'."\n"; |
| 1063 |
echo '</td>'."\n"; |
| 1064 |
|
| 1065 |
echo '</tr>'."\n"; |
| 1066 |
echo '</tbody>'."\n"; |
| 1067 |
echo '</table>'."\n"; |
| 1068 |
|
| 1069 |
//250606 Skip Custom Value Domain Validation. |
| 1070 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 1071 |
|
| 1072 |
echo '<table class="form-table">'."\n"; |
| 1073 |
echo '<tbody>'."\n"; |
| 1074 |
echo '<tr>'."\n"; |
| 1075 |
|
| 1076 |
echo '<th>'."\n"; |
| 1077 |
echo '<label for="ws-plugin--s2member-skip-ipn-domain-validation">'."\n"; |
| 1078 |
echo 'Skip Domain Validation of the `custom` Value? (beta)<br />'."\n"; |
| 1079 |
echo '<small><em class="ws-menu-page-hilite">* This setting applies to all gateways. [ <a href="#" onclick="alert(\'This configuration option may also appear under the other gateways. You can change it here, but remember that this setting is shared among all Payment Gateways integrated with s2Member.\'); return false;">?</a> ]</em></small>'."\n"; |
| 1080 |
echo '</label>'."\n"; |
| 1081 |
echo '</th>'."\n"; |
| 1082 |
|
| 1083 |
echo '</tr>'."\n"; |
| 1084 |
echo '<tr>'."\n"; |
| 1085 |
|
| 1086 |
echo '<td>'."\n"; |
| 1087 |
echo '<input type="radio" name="ws_plugin__s2member_skip_ipn_domain_validation" id="ws-plugin--s2member-skip-ipn-domain-validation-0" value="0"'.((!$GLOBALS['WS_PLUGIN__']['s2member']['o']['skip_ipn_domain_validation']) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-skip-ipn-domain-validation-0">No</label> <input type="radio" name="ws_plugin__s2member_skip_ipn_domain_validation" id="ws-plugin--s2member-skip-ipn-domain-validation-1" value="1"'.(($GLOBALS['WS_PLUGIN__']['s2member']['o']['skip_ipn_domain_validation']) ? ' checked="checked"' : '').' /> <label for="ws-plugin--s2member-skip-ipn-domain-validation-1">Yes, skip domain checks in the `custom` value.</label><br />'."\n"; |
| 1088 |
echo '<em>This allows continued processing of notifications even if the domain in the `custom` value doesn\'t match the current <code>'.esc_html($_SERVER["HTTP_HOST"]).'</code>. Useful for subscriptions originated outside of s2Member, or under a different domain.</em><br />'."\n"; |
| 1089 |
echo '</td>'."\n"; |
| 1090 |
|
| 1091 |
echo '</tr>'."\n"; |
| 1092 |
echo '</tbody>'."\n"; |
| 1093 |
echo '</table>'."\n"; |
| 1094 |
|
| 1095 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 1096 |
|
| 1097 |
echo '<h3 style="margin:0;">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"; |
| 1098 |
echo '<div id="ws-plugin--s2member-paypal-ipn-details" style="margin-top:10px; display:none;">'."\n"; |
| 1099 |
echo '<p><em><strong>IPN History:</strong> Here\'s PayPal\'s <a href="https://s2member.com/r/paypal-ipn-history/" target="_blank" rel="external">Instant Payment Notification (IPN) History page</a>.</em></p>'; |
| 1100 |
echo '<p><em><strong>Quick Tip:</strong> In addition to the <a href="http://s2member.com/r/paypal-com-ipn-configuration-page/" 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"; |
| 1101 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_ipn_after_quick_tip", get_defined_vars()); |
| 1102 |
echo '<p><em><strong>IPN Communications:</strong> You\'ll be happy to know that s2Member handles cancellations, expirations, failed payments, terminations (e.g., refunds & 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 & 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 assigned the role selected under Demote To Role, or have the configured Delete behavior applied automatically. The communication from PayPal → s2Member is seamless.</em></p>'."\n"; |
| 1103 |
echo '</div>'."\n"; |
| 1104 |
|
| 1105 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 1106 |
|
| 1107 |
echo '<h3 style="margin:0;">IPN w/ Proxy Key (<a href="#" onclick="jQuery(\'div#ws-plugin--s2member-paypal-ipn-proxy-details\').toggle(); return false;" class="ws-dotted-link">optional, for 3rd-party integrations</a>)</h3>'."\n"; |
| 1108 |
echo '<div id="ws-plugin--s2member-paypal-ipn-proxy-details" style="margin-top:10px; display:none;">'."\n"; |
| 1109 |
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"; |
| 1110 |
echo '<input type="text" autocomplete="off" value="'.format_to_edit(home_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()), "https")).'" style="width:99%;" />'."\n"; |
| 1111 |
echo '<p><em>Any 3rd-party application that is sending IPN transactions to your s2Member installation must 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="https://s2member.com/r/paypal/-ipn-pdt-vars" target="_blank" rel="external">PayPal\'s IPN/PDT reference guide</a> for full documentation.</em></p>'."\n"; |
| 1112 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_ipn_after_proxy", get_defined_vars()); |
| 1113 |
echo '</div>'."\n"; |
| 1114 |
echo '</div>'."\n"; |
| 1115 |
|
| 1116 |
echo '</div>'."\n"; |
| 1117 |
|
| 1118 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_after_paypal_ipn", get_defined_vars()); |
| 1119 |
} |
| 1120 |
|
| 1121 |
if(apply_filters("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_display_paypal_pdt", TRUE, get_defined_vars())) |
| 1122 |
{ |
| 1123 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_paypal_pdt", get_defined_vars()); |
| 1124 |
|
| 1125 |
echo '<div class="ws-menu-page-group" title="PayPal PDT/Auto-Return Integration">'."\n"; |
| 1126 |
|
| 1127 |
echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-pdt-section">'."\n"; |
| 1128 |
echo '<h3>PayPal PDT Identity Token (required, please enable)</h3>'."\n"; |
| 1129 |
echo '<p>Log into your PayPal account and navigate to this section:<br /><strong><a href="https://www.paypal.com/businessmanage/preferences/website" target="_blank" rel="external">Account Settings → Website Payments → Website Preferences</a></strong></p>'."\n"; |
| 1130 |
echo '<p>Turn the Auto-Return feature: <strong><code>On</code></strong></p>'."\n"; |
| 1131 |
echo '<p>You\'ll need your <a href="'.esc_attr(home_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(home_url("/?s2member_paypal_return=1")).'</code></p>'."\n"; |
| 1132 |
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 can enter below.</em></p>'."\n"; |
| 1133 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_pdt", get_defined_vars()); |
| 1134 |
|
| 1135 |
echo '<table class="form-table">'."\n"; |
| 1136 |
echo '<tbody>'."\n"; |
| 1137 |
echo '<tr>'."\n"; |
| 1138 |
|
| 1139 |
echo '<th>'."\n"; |
| 1140 |
echo '<label for="ws-plugin--s2member-paypal-identity-token">'."\n"; |
| 1141 |
echo 'PayPal PDT Identity Token:'."\n"; |
| 1142 |
echo '</label>'."\n"; |
| 1143 |
echo '</th>'."\n"; |
| 1144 |
|
| 1145 |
echo '</tr>'."\n"; |
| 1146 |
echo '<tr>'."\n"; |
| 1147 |
|
| 1148 |
echo '<td>'."\n"; |
| 1149 |
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"; |
| 1150 |
echo 'Your PDT Identity Token will appear under <strong>Account Settings → Website Payments → Website Preferences</strong> in your PayPal account.'."\n"; |
| 1151 |
echo '</td>'."\n"; |
| 1152 |
|
| 1153 |
echo '</tr>'."\n"; |
| 1154 |
echo '</tbody>'."\n"; |
| 1155 |
echo '</table>'."\n"; |
| 1156 |
|
| 1157 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 1158 |
|
| 1159 |
echo '<h3 style="margin:0;">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"; |
| 1160 |
echo '<div id="ws-plugin--s2member-paypal-pdt-details" style="margin-top:10px; display:none;">'."\n"; |
| 1161 |
echo '<p><em><strong>Quick Tip:</strong> In addition to the <a href="http://s2member.com/r/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 sets the Auto-Return URL (dynamically) 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 by the s2Member software.</em></p>'."\n"; |
| 1162 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_pdt_after_quick_tip", get_defined_vars()); |
| 1163 |
echo '</div>'."\n"; |
| 1164 |
|
| 1165 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_paypal_pdt_after_more_info", get_defined_vars()); |
| 1166 |
|
| 1167 |
echo '</div>'."\n"; |
| 1168 |
|
| 1169 |
echo '</div>'."\n"; |
| 1170 |
|
| 1171 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_after_paypal_pdt", get_defined_vars()); |
| 1172 |
} |
| 1173 |
|
| 1174 |
if(apply_filters("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_display_signup_confirmation_email", TRUE, get_defined_vars())) |
| 1175 |
{ |
| 1176 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_signup_confirmation_email", get_defined_vars()); |
| 1177 |
|
| 1178 |
echo '<div class="ws-menu-page-group" title="Signup Confirmation Email (Standard)">'."\n"; |
| 1179 |
|
| 1180 |
echo '<div class="ws-menu-page-section ws-plugin--s2member-signup-confirmation-email-section">'."\n"; |
| 1181 |
echo '<h3>Signup Confirmation Email (required, but the default works fine)</h3>'."\n"; |
| 1182 |
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"; |
| 1183 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_signup_confirmation_email", get_defined_vars()); |
| 1184 |
|
| 1185 |
echo '<table class="form-table">'."\n"; |
| 1186 |
echo '<tbody>'."\n"; |
| 1187 |
echo '<tr>'."\n"; |
| 1188 |
|
| 1189 |
echo '<th>'."\n"; |
| 1190 |
echo '<label for="ws-plugin--s2member-signup-email-recipients">'."\n"; |
| 1191 |
echo 'Signup Confirmation Recipients:'."\n"; |
| 1192 |
echo '</label>'."\n"; |
| 1193 |
echo '</th>'."\n"; |
| 1194 |
|
| 1195 |
echo '</tr>'."\n"; |
| 1196 |
echo '<tr>'."\n"; |
| 1197 |
|
| 1198 |
echo '<td>'."\n"; |
| 1199 |
echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_signup_email_recipients" id="ws-plugin--s2member-signup-email-recipients" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_email_recipients"]).'" /><br />'."\n"; |
| 1200 |
echo 'This is a semicolon ( ; ) delimited list of Recipients. Here is an example:<br />'."\n"; |
| 1201 |
echo '<code>"%%full_name%%" <%%payer_email%%>; admin@example.com; "Webmaster" <webmaster@example.com></code>'."\n"; |
| 1202 |
echo '</td>'."\n"; |
| 1203 |
|
| 1204 |
echo '</tr>'."\n"; |
| 1205 |
echo '<tr>'."\n"; |
| 1206 |
|
| 1207 |
echo '<th>'."\n"; |
| 1208 |
echo '<label for="ws-plugin--s2member-signup-email-subject">'."\n"; |
| 1209 |
echo 'Signup Confirmation Email Subject:'."\n"; |
| 1210 |
echo '</label>'."\n"; |
| 1211 |
echo '</th>'."\n"; |
| 1212 |
|
| 1213 |
echo '</tr>'."\n"; |
| 1214 |
echo '<tr>'."\n"; |
| 1215 |
|
| 1216 |
echo '<td>'."\n"; |
| 1217 |
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"; |
| 1218 |
echo 'Subject Line used in the email sent to a Customer after a successful signup has occurred through PayPal.'."\n"; |
| 1219 |
echo '</td>'."\n"; |
| 1220 |
|
| 1221 |
echo '</tr>'."\n"; |
| 1222 |
echo '<tr>'."\n"; |
| 1223 |
|
| 1224 |
echo '<th>'."\n"; |
| 1225 |
echo '<label for="ws-plugin--s2member-signup-email-message">'."\n"; |
| 1226 |
echo 'Signup Confirmation Email Message:'."\n"; |
| 1227 |
echo '</label>'."\n"; |
| 1228 |
echo '</th>'."\n"; |
| 1229 |
|
| 1230 |
echo '</tr>'."\n"; |
| 1231 |
echo '<tr>'."\n"; |
| 1232 |
|
| 1233 |
echo '<td>'."\n"; |
| 1234 |
//250615 Visual editor for HTML emails. |
| 1235 |
if (empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['html_emails_enabled'])) { |
| 1236 |
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"; |
| 1237 |
} else { |
| 1238 |
c_ws_plugin__s2member_utilities::editor('signup_email_message'); |
| 1239 |
} |
| 1240 |
|
| 1241 |
echo 'Message Body used in the email sent to a Customer after a successful signup has occurred through PayPal.<br /><br />'."\n"; |
| 1242 |
echo '<strong>You can also use these special Replacement Codes if you need them:</strong>'."\n"; |
| 1243 |
echo '<ul class="ws-menu-page-li-margins">'."\n"; |
| 1244 |
echo '<li><code>%%registration_url%%</code> = The full URL (generated by s2Member) where the Customer can get registered.</li>'."\n"; |
| 1245 |
echo '<li><code>%%subscr_id%%</code> = The PayPal Subscription ID, which remains constant throughout any & 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 & 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"; |
| 1246 |
echo '<li><code>%%currency%%</code> = Three-character currency code (uppercase); e.g., <code>USD</code></li>'."\n"; |
| 1247 |
echo '<li><code>%%currency_symbol%%</code> = Currency code symbol; e.g., <code>$</code></li>'."\n"; |
| 1248 |
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"; |
| 1249 |
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"; |
| 1250 |
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%% & %%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"; |
| 1251 |
echo '<li><code>%%first_name%%</code> = The First Name of the Customer who purchased the Membership Subscription.</li>'."\n"; |
| 1252 |
echo '<li><code>%%last_name%%</code> = The Last Name of the Customer who purchased the Membership Subscription.</li>'."\n"; |
| 1253 |
echo '<li><code>%%full_name%%</code> = The Full Name (First & Last) of the Customer who purchased the Membership Subscription.</li>'."\n"; |
| 1254 |
echo '<li><code>%%payer_email%%</code> = The Email Address of the Customer who purchased the Membership Subscription.</li>'."\n"; |
| 1255 |
echo '<li><code>%%user_ip%%</code> = The Customer\'s IP Address, detected during checkout via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>'."\n"; |
| 1256 |
echo '<li><code>%%item_number%%</code> = The Item Number (colon separated <code><em>level:custom_capabilities:fixed term</em></code>) that the Subscription is for.</li>'."\n"; |
| 1257 |
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"; |
| 1258 |
echo '<li><code>%%initial_term%%</code> = This is the term length of the Initial Period. This will be a numeric value, followed by a space, then a single letter. [ <a href="#" onclick="alert(\'Here are some examples:\\n\\n%%initial_term%% = 1 D (this means 1 Day)\\n%%initial_term%% = 1 W (this means 1 Week)\\n%%initial_term%% = 1 M (this means 1 Month)\\n%%initial_term%% = 1 Y (this means 1 Year)\\n\\nThe Initial Period never recurs, so this only lasts for the term length specified, then it is over.\'); return false;">?</a> ]</li>'."\n"; |
| 1259 |
echo '<li><code>%%initial_cycle%%</code> = This is the <code>%%initial_term%%</code> from above, converted to a cycle representation of: <code><em>X days/weeks/months/years</em></code>.</li>'."\n"; |
| 1260 |
echo '<li><code>%%regular_term%%</code> = This is the term length of the Regular Period. This will be a numeric value, followed by a space, then a single letter. [ <a href="#" onclick="alert(\'Here are some examples:\\n\\n%%regular_term%% = 1 D (this means 1 Day)\\n%%regular_term%% = 1 W (this means 1 Week)\\n%%regular_term%% = 1 M (this means 1 Month)\\n%%regular_term%% = 1 Y (this means 1 Year)\\n%%regular_term%% = 1 L (this means 1 Lifetime)\\n\\nThe Regular Term is usually recurring. So the Regular Term value represents the period (or duration) of each recurring period. If %%recurring%% = 0, then the Regular Term only applies once, because it is not recurring. So if it is not recurring, the value of %%regular_term%% simply represents how long their Membership privileges are going to last after the %%initial_term%% has expired, if there was an Initial Term. The value of this variable ( %%regular_term%% ) will never be empty, it will always be at least: 1 D, meaning 1 day. No exceptions.\'); return false;">?</a> ]</li>'."\n"; |
| 1261 |
echo '<li><code>%%regular_cycle%%</code> = This is the <code>%%regular_term%%</code> from above, converted to a cycle representation of: <code><em>[every] X days/weeks/months/years—OR daily, weekly, bi-weekly, monthly, bi-monthly, quarterly, yearly, or lifetime</em></code>. This is a very useful Replacment Code. Its value is dynamic; depending on term length, recurring status, and period/term lengths configured.</li>'."\n"; |
| 1262 |
echo '<li><code>%%recurring/regular_cycle%%</code> = Example (<code>14.95 / Monthly</code>), or ... (<code>0 / non-recurring</code>); depending on the value of <code>%%recurring%%</code>.</li>'."\n"; |
| 1263 |
echo '</ul>'."\n"; |
| 1264 |
|
| 1265 |
echo '<strong>Custom Replacement Codes can also be inserted using these instructions:</strong>'."\n"; |
| 1266 |
echo '<ul class="ws-menu-page-li-margins">'."\n"; |
| 1267 |
echo '<li><code>%%cv0%%</code> = The domain of your site, which is passed through the `custom` attribute in your Shortcode.</li>'."\n"; |
| 1268 |
echo '<li><code>%%cv1%%</code> = If you need to track additional custom variables, you can pipe delimit them into the `custom` attribute; inside your Shortcode, like this: <code>custom="'.esc_html($_SERVER["HTTP_HOST"]).'|cv1|cv2|cv3"</code>. You can have an unlimited number of custom variables. Obviously, this is for advanced webmasters; but the functionality has been made available for those who need it.</li>'."\n"; |
| 1269 |
echo '</ul>'."\n"; |
| 1270 |
echo '<strong>This example uses cv1 to record a special marketing campaign:</strong><br />'."\n"; |
| 1271 |
echo '<em>(The campaign (i.e., christmas-promo) could be referenced using <code>%%cv1%%</code>)</em><br />'."\n"; |
| 1272 |
echo '<code>custom="'.esc_html($_SERVER["HTTP_HOST"]).'|christmas-promo"</code>'."\n"; |
| 1273 |
|
| 1274 |
echo (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) ? |
| 1275 |
'<div class="ws-menu-page-hr"></div>'."\n". |
| 1276 |
'<p style="margin:0;"><strong>Advanced Customization:</strong> Further customization is possible with the <code>ws_plugin__s2member_signup_email_sbj</code> and <code>ws_plugin__s2member_signup_email_msg</code> filters from a plugin or theme.</p>'."\n" |
| 1277 |
: ''; |
| 1278 |
echo '</td>'."\n"; |
| 1279 |
|
| 1280 |
echo '</tr>'."\n"; |
| 1281 |
echo '</tbody>'."\n"; |
| 1282 |
echo '</table>'."\n"; |
| 1283 |
echo '</div>'."\n"; |
| 1284 |
|
| 1285 |
echo '</div>'."\n"; |
| 1286 |
|
| 1287 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_after_signup_confirmation_email", get_defined_vars()); |
| 1288 |
} |
| 1289 |
|
| 1290 |
if(apply_filters("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_display_modification_confirmation_email", c_ws_plugin__s2member_utils_conds::pro_is_installed(), get_defined_vars())) |
| 1291 |
{ |
| 1292 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_modification_confirmation_email", get_defined_vars()); |
| 1293 |
|
| 1294 |
echo '<div class="ws-menu-page-group" title="Modification Confirmation Email '.((c_ws_plugin__s2member_utils_conds::pro_is_installed()) ? '(Standard/Pro-Form)' : '(Standard)').'">'."\n"; |
| 1295 |
|
| 1296 |
echo '<div class="ws-menu-page-section ws-plugin--s2member-modification-confirmation-email-section">'."\n"; |
| 1297 |
echo '<h3>Modification Confirmation Email (required, but the default works fine)</h3>'."\n"; |
| 1298 |
echo '<p>This email is sent to existing Users after they complete an upgrade/downgrade (if and when you make this possible). For instance, if a Free Subscriber upgrades to a paid Membership Level, s2Member considers this a Modification (NOT a Signup; a Signup is associated only with someone completely new). The <strong>primary</strong> purpose of this email is to provide the Customer with a confirmation that their account was updated. You may also customize this further by providing details that are specifically geared to your site.</p>'."\n"; |
| 1299 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_modification_confirmation_email", get_defined_vars()); |
| 1300 |
|
| 1301 |
echo '<table class="form-table">'."\n"; |
| 1302 |
echo '<tbody>'."\n"; |
| 1303 |
echo '<tr>'."\n"; |
| 1304 |
|
| 1305 |
echo '<th>'."\n"; |
| 1306 |
echo '<label for="ws-plugin--s2member-modification-email-recipients">'."\n"; |
| 1307 |
echo 'Modification Confirmation Recipients:'."\n"; |
| 1308 |
echo '</label>'."\n"; |
| 1309 |
echo '</th>'."\n"; |
| 1310 |
|
| 1311 |
echo '</tr>'."\n"; |
| 1312 |
echo '<tr>'."\n"; |
| 1313 |
|
| 1314 |
echo '<td>'."\n"; |
| 1315 |
echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_modification_email_recipients" id="ws-plugin--s2member-modification-email-recipients" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["modification_email_recipients"]).'" /><br />'."\n"; |
| 1316 |
echo 'This is a semicolon ( ; ) delimited list of Recipients. Here is an example:<br />'."\n"; |
| 1317 |
echo '<code>"%%full_name%%" <%%payer_email%%>; admin@example.com; "Webmaster" <webmaster@example.com></code>'."\n"; |
| 1318 |
echo '</td>'."\n"; |
| 1319 |
|
| 1320 |
echo '</tr>'."\n"; |
| 1321 |
echo '<tr>'."\n"; |
| 1322 |
|
| 1323 |
echo '<th>'."\n"; |
| 1324 |
echo '<label for="ws-plugin--s2member-modification-email-subject">'."\n"; |
| 1325 |
echo 'Modification Confirmation Email Subject:'."\n"; |
| 1326 |
echo '</label>'."\n"; |
| 1327 |
echo '</th>'."\n"; |
| 1328 |
|
| 1329 |
echo '</tr>'."\n"; |
| 1330 |
echo '<tr>'."\n"; |
| 1331 |
|
| 1332 |
echo '<td>'."\n"; |
| 1333 |
echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_modification_email_subject" id="ws-plugin--s2member-modification-email-subject" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["modification_email_subject"]).'" /><br />'."\n"; |
| 1334 |
echo 'Subject Line used in the email sent to a Customer after a successful modification has occurred through PayPal.'."\n"; |
| 1335 |
echo '</td>'."\n"; |
| 1336 |
|
| 1337 |
echo '</tr>'."\n"; |
| 1338 |
echo '<tr>'."\n"; |
| 1339 |
|
| 1340 |
echo '<th>'."\n"; |
| 1341 |
echo '<label for="ws-plugin--s2member-modification-email-message">'."\n"; |
| 1342 |
echo 'Modification Confirmation Email Message:'."\n"; |
| 1343 |
echo '</label>'."\n"; |
| 1344 |
echo '</th>'."\n"; |
| 1345 |
|
| 1346 |
echo '</tr>'."\n"; |
| 1347 |
echo '<tr>'."\n"; |
| 1348 |
|
| 1349 |
echo '<td>'."\n"; |
| 1350 |
//250615 Visual editor for HTML emails. |
| 1351 |
if (empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['html_emails_enabled'])) { |
| 1352 |
echo '<textarea name="ws_plugin__s2member_modification_email_message" id="ws-plugin--s2member-modification-email-message" rows="10">'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["modification_email_message"]).'</textarea><br />'."\n"; |
| 1353 |
} else { |
| 1354 |
c_ws_plugin__s2member_utilities::editor('modification_email_message'); |
| 1355 |
} |
| 1356 |
|
| 1357 |
echo 'Message Body used in the email sent to a Customer after a successful modification has occurred through PayPal.<br /><br />'."\n"; |
| 1358 |
echo '<strong>You can also use these special Replacement Codes if you need them:</strong>'."\n"; |
| 1359 |
echo '<ul class="ws-menu-page-li-margins">'."\n"; |
| 1360 |
echo '<li><code>%%subscr_id%%</code> = The PayPal Subscription ID, which remains constant throughout any & 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 & 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"; |
| 1361 |
echo '<li><code>%%subscr_baid%%</code> = Applicable only with PayPal Pro (Payflow Edition); and only for Express Checkout transactions that require a Billing Agreement. This is the Subscription\'s Billing Agreement ID, which remains constant throughout any & all future payments. [ <a href="#" onclick="alert(\'Applicable only with PayPal Pro (Payflow Edition); and only for Express Checkout transactions that require a Billing Agreement. In all other cases, the %%subscr_baid%% is simply set to the %%subscr_id%% value; i.e., it is a duplicate of %%subscr_id%% in most cases.\'); return false;">?</a> ]</li>'."\n"; |
| 1362 |
echo '<li><code>%%currency%%</code> = Three-character currency code (uppercase); e.g., <code>USD</code></li>'."\n"; |
| 1363 |
echo '<li><code>%%currency_symbol%%</code> = Currency code symbol; e.g., <code>$</code></li>'."\n"; |
| 1364 |
echo '<li><code>%%initial%%</code> = The Initial Fee. 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 when they completed checkout, no matter what. Even if that amount is 0. If a Customer upgrades/downgrades under the terms of a 100% Free Trial Period, this will be 0.\'); return false;">?</a> ]</li>'."\n"; |
| 1365 |
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"; |
| 1366 |
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%% & %%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"; |
| 1367 |
echo '<li><code>%%first_name%%</code> = The First Name of the Customer who purchased the Membership Subscription.</li>'."\n"; |
| 1368 |
echo '<li><code>%%last_name%%</code> = The Last Name of the Customer who purchased the Membership Subscription.</li>'."\n"; |
| 1369 |
echo '<li><code>%%full_name%%</code> = The Full Name (First & Last) of the Customer who purchased the Membership Subscription.</li>'."\n"; |
| 1370 |
echo '<li><code>%%payer_email%%</code> = The Email Address of the Customer who purchased the Membership Subscription.</li>'."\n"; |
| 1371 |
echo '<li><code>%%item_number%%</code> = The Item Number (colon separated <code><em>level:custom_capabilities:fixed term</em></code>) that the Subscription is for.</li>'."\n"; |
| 1372 |
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"; |
| 1373 |
echo '<li><code>%%initial_term%%</code> = This is the term length of the Initial Period. This will be a numeric value, followed by a space, then a single letter. [ <a href="#" onclick="alert(\'Here are some examples:\\n\\n%%initial_term%% = 1 D (this means 1 Day)\\n%%initial_term%% = 1 W (this means 1 Week)\\n%%initial_term%% = 1 M (this means 1 Month)\\n%%initial_term%% = 1 Y (this means 1 Year)\\n\\nThe Initial Period never recurs, so this only lasts for the term length specified, then it is over.\'); return false;">?</a> ]</li>'."\n"; |
| 1374 |
echo '<li><code>%%initial_cycle%%</code> = This is the <code>%%initial_term%%</code> from above, converted to a cycle representation of: <code><em>X days/weeks/months/years</em></code>.</li>'."\n"; |
| 1375 |
echo '<li><code>%%regular_term%%</code> = This is the term length of the Regular Period. This will be a numeric value, followed by a space, then a single letter. [ <a href="#" onclick="alert(\'Here are some examples:\\n\\n%%regular_term%% = 1 D (this means 1 Day)\\n%%regular_term%% = 1 W (this means 1 Week)\\n%%regular_term%% = 1 M (this means 1 Month)\\n%%regular_term%% = 1 Y (this means 1 Year)\\n%%regular_term%% = 1 L (this means 1 Lifetime)\\n\\nThe Regular Term is usually recurring. So the Regular Term value represents the period (or duration) of each recurring period. If %%recurring%% = 0, then the Regular Term only applies once, because it is not recurring. So if it is not recurring, the value of %%regular_term%% simply represents how long their Membership privileges are going to last after the %%initial_term%% has expired, if there was an Initial Term. The value of this variable ( %%regular_term%% ) will never be empty, it will always be at least: 1 D, meaning 1 day. No exceptions.\'); return false;">?</a> ]</li>'."\n"; |
| 1376 |
echo '<li><code>%%regular_cycle%%</code> = This is the <code>%%regular_term%%</code> from above, converted to a cycle representation of: <code><em>[every] X days/weeks/months/years—OR daily, weekly, bi-weekly, monthly, bi-monthly, quarterly, yearly, or lifetime</em></code>. This is a very useful Replacment Code. Its value is dynamic; depending on term length, recurring status, and period/term lengths configured.</li>'."\n"; |
| 1377 |
echo '<li><code>%%recurring/regular_cycle%%</code> = Example (<code>14.95 / Monthly</code>), or ... (<code>0 / non-recurring</code>); depending on the value of <code>%%recurring%%</code>.</li>'."\n"; |
| 1378 |
echo '<li><code>%%user_first_name%%</code> = The First Name listed on their User account. This might be different than what is on file with PayPal.</li>'."\n"; |
| 1379 |
echo '<li><code>%%user_last_name%%</code> = The Last Name listed on their User account. This might be different than what is on file with PayPal.</li>'."\n"; |
| 1380 |
echo '<li><code>%%user_full_name%%</code> = The Full Name listed on their User account. This might be different than what is on file with PayPal.</li>'."\n"; |
| 1381 |
echo '<li><code>%%user_email%%</code> = The Email Address associated with their User account. This might be different than what is on file with PayPal.</li>'."\n"; |
| 1382 |
echo '<li><code>%%user_login%%</code> = The Username associated with their account. The Customer created this during registration.</li>'."\n"; |
| 1383 |
echo '<li><code>%%user_ip%%</code> = The Customer\'s original IP Address, during checkout/registration via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>'."\n"; |
| 1384 |
echo '<li><code>%%user_id%%</code> = A unique WordPress User ID that references this account in the WordPress database.</li>'."\n"; |
| 1385 |
echo '</ul>'."\n"; |
| 1386 |
|
| 1387 |
if(c_ws_plugin__s2member_utils_conds::pro_is_installed()) |
| 1388 |
{ |
| 1389 |
echo '<strong>Coupon Replacement Codes (applicable only w/ s2Member Pro-Forms):</strong>'."\n"; |
| 1390 |
echo '<ul class="ws-menu-page-li-margins">'."\n"; |
| 1391 |
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 (i.e., the full Coupon Code).</li>'."\n"; |
| 1392 |
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"; |
| 1393 |
echo '<li><code>%%coupon_affiliate_id%%</code> = This is the end of an Affiliate Coupon Code <em>(i.e., the referring affiliate\'s ID)</em>. This is only applicable if an Affiliate Coupon Code is accepted by your configuration of s2Member.</li>'."\n"; |
| 1394 |
echo '</ul>'."\n"; |
| 1395 |
} |
| 1396 |
echo '<strong>Custom Registration/Profile Fields are also supported in this email:</strong>'."\n"; |
| 1397 |
echo '<ul class="ws-menu-page-li-margins">'."\n"; |
| 1398 |
echo '<li><code>%%date_of_birth%%</code> would be valid; if you have a Custom Registration/Profile Field with the ID <code>date_of_birth</code>.</li>'."\n"; |
| 1399 |
echo '<li><code>%%street_address%%</code> would be valid; if you have a Custom Registration/Profile Field with the ID <code>street_address</code>.</li>'."\n"; |
| 1400 |
echo '<li><code>%%country%%</code> would be valid; if you have a Custom Registration/Profile Field with the ID <code>country</code>.</li>'."\n"; |
| 1401 |
echo '<li><em><code>%%etc, etc...%%</code> <strong>see:</strong> s2Member → General Options → Registration/Profile Fields</em>.</li>'."\n"; |
| 1402 |
echo '</ul>'."\n"; |
| 1403 |
|
| 1404 |
echo '<strong>Custom Replacement Codes can also be inserted using these instructions:</strong>'."\n"; |
| 1405 |
echo '<ul class="ws-menu-page-li-margins">'."\n"; |
| 1406 |
echo '<li><code>%%cv0%%</code> = The domain of your site, which is passed through the `custom` attribute in your Shortcode.</li>'."\n"; |
| 1407 |
echo '<li><code>%%cv1%%</code> = If you need to track additional custom variables, you can pipe delimit them into the `custom` attribute; inside your Shortcode, like this: <code>custom="'.esc_html($_SERVER["HTTP_HOST"]).'|cv1|cv2|cv3"</code>. You can have an unlimited number of custom variables. Obviously, this is for advanced webmasters; but the functionality has been made available for those who need it.</li>'."\n"; |
| 1408 |
echo '</ul>'."\n"; |
| 1409 |
echo '<strong>This example uses cv1 to record a special marketing campaign:</strong><br />'."\n"; |
| 1410 |
echo '<em>(The campaign (i.e., christmas-promo) could be referenced using <code>%%cv1%%</code>)</em><br />'."\n"; |
| 1411 |
echo '<code>custom="'.esc_html($_SERVER["HTTP_HOST"]).'|christmas-promo"</code>'."\n"; |
| 1412 |
|
| 1413 |
echo (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) ? |
| 1414 |
'<div class="ws-menu-page-hr"></div>'."\n". |
| 1415 |
'<p style="margin:0;"><strong>Advanced Customization:</strong> Further customization is possible with the <code>ws_plugin__s2member_modification_email_sbj</code> and <code>ws_plugin__s2member_modification_email_msg</code> filters from a plugin or theme.</p>'."\n" |
| 1416 |
: ''; |
| 1417 |
echo '</td>'."\n"; |
| 1418 |
|
| 1419 |
echo '</tr>'."\n"; |
| 1420 |
echo '</tbody>'."\n"; |
| 1421 |
echo '</table>'."\n"; |
| 1422 |
echo '</div>'."\n"; |
| 1423 |
|
| 1424 |
echo '</div>'."\n"; |
| 1425 |
|
| 1426 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_after_modification_confirmation_email", get_defined_vars()); |
| 1427 |
} |
| 1428 |
|
| 1429 |
if(apply_filters("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_display_ccap_confirmation_email", c_ws_plugin__s2member_utils_conds::pro_is_installed(), get_defined_vars())) |
| 1430 |
{ |
| 1431 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_ccap_confirmation_email", get_defined_vars()); |
| 1432 |
|
| 1433 |
echo '<div class="ws-menu-page-group" title="Capability Confirmation Email '.((c_ws_plugin__s2member_utils_conds::pro_is_installed()) ? '(Standard/Pro-Form)' : '(Standard)').'">'."\n"; |
| 1434 |
|
| 1435 |
echo '<div class="ws-menu-page-section ws-plugin--s2member-ccap-confirmation-email-section">'."\n"; |
| 1436 |
echo '<h3>Capability Confirmation Email (required, but the default works fine)</h3>'."\n"; |
| 1437 |
echo '<p>This email is sent to existing Users after they complete a Buy Now purchase for one or more Custom Capabilities (if and when you make this possible); see: <strong>Dashboard → s2Member → PayPal Buttons/Forms → Capability (Buy Now)</strong>. The <strong>primary</strong> purpose of this email is to provide the Customer with a confirmation that their account was updated. You may also customize this further by providing details that are specifically geared to your site.</p>'."\n"; |
| 1438 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_ccap_confirmation_email", get_defined_vars()); |
| 1439 |
|
| 1440 |
echo '<table class="form-table">'."\n"; |
| 1441 |
echo '<tbody>'."\n"; |
| 1442 |
echo '<tr>'."\n"; |
| 1443 |
|
| 1444 |
echo '<th>'."\n"; |
| 1445 |
echo '<label for="ws-plugin--s2member-ccap-email-recipients">'."\n"; |
| 1446 |
echo 'Capability Confirmation Recipients:'."\n"; |
| 1447 |
echo '</label>'."\n"; |
| 1448 |
echo '</th>'."\n"; |
| 1449 |
|
| 1450 |
echo '</tr>'."\n"; |
| 1451 |
echo '<tr>'."\n"; |
| 1452 |
|
| 1453 |
echo '<td>'."\n"; |
| 1454 |
echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_ccap_email_recipients" id="ws-plugin--s2member-ccap-email-recipients" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["ccap_email_recipients"]).'" /><br />'."\n"; |
| 1455 |
echo 'This is a semicolon ( ; ) delimited list of Recipients. Here is an example:<br />'."\n"; |
| 1456 |
echo '<code>"%%full_name%%" <%%payer_email%%>; admin@example.com; "Webmaster" <webmaster@example.com></code>'."\n"; |
| 1457 |
echo '</td>'."\n"; |
| 1458 |
|
| 1459 |
echo '</tr>'."\n"; |
| 1460 |
echo '<tr>'."\n"; |
| 1461 |
|
| 1462 |
echo '<th>'."\n"; |
| 1463 |
echo '<label for="ws-plugin--s2member-ccap-email-subject">'."\n"; |
| 1464 |
echo 'Capability Confirmation Email Subject:'."\n"; |
| 1465 |
echo '</label>'."\n"; |
| 1466 |
echo '</th>'."\n"; |
| 1467 |
|
| 1468 |
echo '</tr>'."\n"; |
| 1469 |
echo '<tr>'."\n"; |
| 1470 |
|
| 1471 |
echo '<td>'."\n"; |
| 1472 |
echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_ccap_email_subject" id="ws-plugin--s2member-ccap-email-subject" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["ccap_email_subject"]).'" /><br />'."\n"; |
| 1473 |
echo 'Subject Line used in the email sent to a Customer after a purchase is completed through PayPal.'."\n"; |
| 1474 |
echo '</td>'."\n"; |
| 1475 |
|
| 1476 |
echo '</tr>'."\n"; |
| 1477 |
echo '<tr>'."\n"; |
| 1478 |
|
| 1479 |
echo '<th>'."\n"; |
| 1480 |
echo '<label for="ws-plugin--s2member-ccap-email-message">'."\n"; |
| 1481 |
echo 'Capability Confirmation Email Message:'."\n"; |
| 1482 |
echo '</label>'."\n"; |
| 1483 |
echo '</th>'."\n"; |
| 1484 |
|
| 1485 |
echo '</tr>'."\n"; |
| 1486 |
echo '<tr>'."\n"; |
| 1487 |
|
| 1488 |
echo '<td>'."\n"; |
| 1489 |
//250615 Visual editor for HTML emails. |
| 1490 |
if (empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['html_emails_enabled'])) { |
| 1491 |
echo '<textarea name="ws_plugin__s2member_ccap_email_message" id="ws-plugin--s2member-ccap-email-message" rows="10">'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["ccap_email_message"]).'</textarea><br />'."\n"; |
| 1492 |
} else { |
| 1493 |
c_ws_plugin__s2member_utilities::editor('ccap_email_message'); |
| 1494 |
} |
| 1495 |
|
| 1496 |
echo 'Message Body used in the email sent to a Customer after a purchase is completed through PayPal.<br /><br />'."\n"; |
| 1497 |
echo '<strong>You can also use these special Replacement Codes if you need them:</strong>'."\n"; |
| 1498 |
echo '<ul class="ws-menu-page-li-margins">'."\n"; |
| 1499 |
echo '<li><code>%%txn_id%%</code> = The PayPal Transaction ID. PayPal assigns a unique identifier for every purchase.</li>'."\n"; |
| 1500 |
echo '<li><code>%%currency%%</code> = Three-character currency code (uppercase); e.g., <code>USD</code></li>'."\n"; |
| 1501 |
echo '<li><code>%%currency_symbol%%</code> = Currency code symbol; e.g., <code>$</code></li>'."\n"; |
| 1502 |
echo '<li><code>%%amount%%</code> = The full Amount that you charged for Custom Capability access.</li>'."\n"; |
| 1503 |
echo '<li><code>%%first_name%%</code> = The First Name of the Customer who completed the purchase.</li>'."\n"; |
| 1504 |
echo '<li><code>%%last_name%%</code> = The Last Name of the Customer who completed the purchase.</li>'."\n"; |
| 1505 |
echo '<li><code>%%full_name%%</code> = The Full Name (First & Last) of the Customer who completed the purchase.</li>'."\n"; |
| 1506 |
echo '<li><code>%%payer_email%%</code> = The Email Address of the Customer who completed the purchase.</li>'."\n"; |
| 1507 |
echo '<li><code>%%item_number%%</code> = The Item Number (colon separated <code><em>*:custom_capabilities</em></code>); where <code>custom_capabilities</code> is a comma-delimited list of the Custom Capabilities they purchased.</li>'."\n"; |
| 1508 |
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"; |
| 1509 |
echo '<li><code>%%user_first_name%%</code> = The First Name listed on their User account. This might be different than what is on file with PayPal.</li>'."\n"; |
| 1510 |
echo '<li><code>%%user_last_name%%</code> = The Last Name listed on their User account. This might be different than what is on file with PayPal.</li>'."\n"; |
| 1511 |
echo '<li><code>%%user_full_name%%</code> = The Full Name listed on their User account. This might be different than what is on file with PayPal.</li>'."\n"; |
| 1512 |
echo '<li><code>%%user_email%%</code> = The Email Address associated with their User account. This might be different than what is on file with PayPal.</li>'."\n"; |
| 1513 |
echo '<li><code>%%user_login%%</code> = The Username associated with their account. The Customer created this during registration.</li>'."\n"; |
| 1514 |
echo '<li><code>%%user_ip%%</code> = The Customer\'s original IP Address, during checkout/registration via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>'."\n"; |
| 1515 |
echo '<li><code>%%user_id%%</code> = A unique WordPress User ID that references this account in the WordPress database.</li>'."\n"; |
| 1516 |
echo '</ul>'."\n"; |
| 1517 |
|
| 1518 |
if(c_ws_plugin__s2member_utils_conds::pro_is_installed()) |
| 1519 |
{ |
| 1520 |
echo '<strong>Coupon Replacement Codes (applicable only w/ s2Member Pro-Forms):</strong>'."\n"; |
| 1521 |
echo '<ul class="ws-menu-page-li-margins">'."\n"; |
| 1522 |
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 (i.e., the full Coupon Code).</li>'."\n"; |
| 1523 |
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"; |
| 1524 |
echo '<li><code>%%coupon_affiliate_id%%</code> = This is the end of an Affiliate Coupon Code <em>(i.e., the referring affiliate\'s ID)</em>. This is only applicable if an Affiliate Coupon Code is accepted by your configuration of s2Member.</li>'."\n"; |
| 1525 |
echo '</ul>'."\n"; |
| 1526 |
} |
| 1527 |
echo '<strong>Custom Registration/Profile Fields are also supported in this email:</strong>'."\n"; |
| 1528 |
echo '<ul class="ws-menu-page-li-margins">'."\n"; |
| 1529 |
echo '<li><code>%%date_of_birth%%</code> would be valid; if you have a Custom Registration/Profile Field with the ID <code>date_of_birth</code>.</li>'."\n"; |
| 1530 |
echo '<li><code>%%street_address%%</code> would be valid; if you have a Custom Registration/Profile Field with the ID <code>street_address</code>.</li>'."\n"; |
| 1531 |
echo '<li><code>%%country%%</code> would be valid; if you have a Custom Registration/Profile Field with the ID <code>country</code>.</li>'."\n"; |
| 1532 |
echo '<li><em><code>%%etc, etc...%%</code> <strong>see:</strong> s2Member → General Options → Registration/Profile Fields</em>.</li>'."\n"; |
| 1533 |
echo '</ul>'."\n"; |
| 1534 |
|
| 1535 |
echo '<strong>Custom Replacement Codes can also be inserted using these instructions:</strong>'."\n"; |
| 1536 |
echo '<ul class="ws-menu-page-li-margins">'."\n"; |
| 1537 |
echo '<li><code>%%cv0%%</code> = The domain of your site, which is passed through the `custom` attribute in your Shortcode.</li>'."\n"; |
| 1538 |
echo '<li><code>%%cv1%%</code> = If you need to track additional custom variables, you can pipe delimit them into the `custom` attribute; inside your Shortcode, like this: <code>custom="'.esc_html($_SERVER["HTTP_HOST"]).'|cv1|cv2|cv3"</code>. You can have an unlimited number of custom variables. Obviously, this is for advanced webmasters; but the functionality has been made available for those who need it.</li>'."\n"; |
| 1539 |
echo '</ul>'."\n"; |
| 1540 |
echo '<strong>This example uses cv1 to record a special marketing campaign:</strong><br />'."\n"; |
| 1541 |
echo '<em>(The campaign (i.e., christmas-promo) could be referenced using <code>%%cv1%%</code>)</em><br />'."\n"; |
| 1542 |
echo '<code>custom="'.esc_html($_SERVER["HTTP_HOST"]).'|christmas-promo"</code>'."\n"; |
| 1543 |
|
| 1544 |
echo (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) ? |
| 1545 |
'<div class="ws-menu-page-hr"></div>'."\n". |
| 1546 |
'<p style="margin:0;"><strong>Advanced Customization:</strong> Further customization is possible with the <code>ws_plugin__s2member_capabilities_email_sbj</code> and <code>ws_plugin__s2member_capabilities_email_msg</code> filters from a plugin or theme.</p>'."\n" |
| 1547 |
: ''; |
| 1548 |
echo '</td>'."\n"; |
| 1549 |
|
| 1550 |
echo '</tr>'."\n"; |
| 1551 |
echo '</tbody>'."\n"; |
| 1552 |
echo '</table>'."\n"; |
| 1553 |
echo '</div>'."\n"; |
| 1554 |
|
| 1555 |
echo '</div>'."\n"; |
| 1556 |
|
| 1557 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_after_ccap_confirmation_email", get_defined_vars()); |
| 1558 |
} |
| 1559 |
|
| 1560 |
if(apply_filters("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_display_sp_confirmation_email", TRUE, get_defined_vars())) |
| 1561 |
{ |
| 1562 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_sp_confirmation_email", get_defined_vars()); |
| 1563 |
|
| 1564 |
echo '<div class="ws-menu-page-group" title="Specific Post/Page Confirmation Email (Standard)">'."\n"; |
| 1565 |
|
| 1566 |
echo '<div class="ws-menu-page-section ws-plugin--s2member-sp-confirmation-email-section">'."\n"; |
| 1567 |
echo '<h3>Specific Post/Page Confirmation Email (required, but the default works fine)</h3>'."\n"; |
| 1568 |
echo '<p>This email is sent to new Customers after they return from a successful purchase at PayPal, for Specific Post/Page Access. (see: <strong>s2Member → Restriction Options → Specific Post/Page Access</strong>). 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"; |
| 1569 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_sp_confirmation_email", get_defined_vars()); |
| 1570 |
|
| 1571 |
echo '<table class="form-table">'."\n"; |
| 1572 |
echo '<tbody>'."\n"; |
| 1573 |
echo '<tr>'."\n"; |
| 1574 |
|
| 1575 |
echo '<th>'."\n"; |
| 1576 |
echo '<label for="ws-plugin--s2member-sp-email-recipients">'."\n"; |
| 1577 |
echo 'Specific Post/Page Confirmation Recipients:'."\n"; |
| 1578 |
echo '</label>'."\n"; |
| 1579 |
echo '</th>'."\n"; |
| 1580 |
|
| 1581 |
echo '</tr>'."\n"; |
| 1582 |
echo '<tr>'."\n"; |
| 1583 |
|
| 1584 |
echo '<td>'."\n"; |
| 1585 |
echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_sp_email_recipients" id="ws-plugin--s2member-sp-email-recipients" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sp_email_recipients"]).'" /><br />'."\n"; |
| 1586 |
echo 'This is a semicolon ( ; ) delimited list of Recipients. Here is an example:<br />'."\n"; |
| 1587 |
echo '<code>"%%full_name%%" <%%payer_email%%>; admin@example.com; "Webmaster" <webmaster@example.com></code>'."\n"; |
| 1588 |
echo '</td>'."\n"; |
| 1589 |
|
| 1590 |
echo '</tr>'."\n"; |
| 1591 |
echo '<tr>'."\n"; |
| 1592 |
|
| 1593 |
echo '<th>'."\n"; |
| 1594 |
echo '<label for="ws-plugin--s2member-sp-email-subject">'."\n"; |
| 1595 |
echo 'Specific Post/Page Confirmation Email Subject:'."\n"; |
| 1596 |
echo '</label>'."\n"; |
| 1597 |
echo '</th>'."\n"; |
| 1598 |
|
| 1599 |
echo '</tr>'."\n"; |
| 1600 |
echo '<tr>'."\n"; |
| 1601 |
|
| 1602 |
echo '<td>'."\n"; |
| 1603 |
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"; |
| 1604 |
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"; |
| 1605 |
echo '</td>'."\n"; |
| 1606 |
|
| 1607 |
echo '</tr>'."\n"; |
| 1608 |
echo '<tr>'."\n"; |
| 1609 |
|
| 1610 |
echo '<th>'."\n"; |
| 1611 |
echo '<label for="ws-plugin--s2member-sp-email-message">'."\n"; |
| 1612 |
echo 'Specific Post/Page Confirmation Email Message:'."\n"; |
| 1613 |
echo '</label>'."\n"; |
| 1614 |
echo '</th>'."\n"; |
| 1615 |
|
| 1616 |
echo '</tr>'."\n"; |
| 1617 |
echo '<tr>'."\n"; |
| 1618 |
|
| 1619 |
echo '<td>'."\n"; |
| 1620 |
//250615 Visual editor for HTML emails. |
| 1621 |
if (empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['html_emails_enabled'])) { |
| 1622 |
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"; |
| 1623 |
} else { |
| 1624 |
c_ws_plugin__s2member_utilities::editor('sp_email_message'); |
| 1625 |
} |
| 1626 |
|
| 1627 |
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"; |
| 1628 |
echo '<strong>You can also use these special Replacement Codes if you need them:</strong>'."\n"; |
| 1629 |
echo '<ul class="ws-menu-page-li-margins">'."\n"; |
| 1630 |
echo '<li><code>%%sp_access_url%%</code> = The full URL (generated by s2Member) where the Customer can gain access.</li>'."\n"; |
| 1631 |
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"; |
| 1632 |
echo '<li><code>%%txn_id%%</code> = The PayPal Transaction ID. PayPal assigns a unique identifier for every purchase.</li>'."\n"; |
| 1633 |
echo '<li><code>%%currency%%</code> = Three-character currency code (uppercase); e.g., <code>USD</code></li>'."\n"; |
| 1634 |
echo '<li><code>%%currency_symbol%%</code> = Currency code symbol; e.g., <code>$</code></li>'."\n"; |
| 1635 |
echo '<li><code>%%amount%%</code> = The full Amount that you charged for Specific Post/Page Access.</li>'."\n"; |
| 1636 |
echo '<li><code>%%first_name%%</code> = The First Name of the Customer who purchased Specific Post/Page Access.</li>'."\n"; |
| 1637 |
echo '<li><code>%%last_name%%</code> = The Last Name of the Customer who purchased Specific Post/Page Access.</li>'."\n"; |
| 1638 |
echo '<li><code>%%full_name%%</code> = The Full Name (First & Last) of the Customer who purchased Specific Post/Page Access.</li>'."\n"; |
| 1639 |
echo '<li><code>%%payer_email%%</code> = The Email Address of the Customer who purchased Specific Post/Page Access.</li>'."\n"; |
| 1640 |
echo '<li><code>%%user_ip%%</code> = The Customer\'s IP Address, detected during checkout via <code>$_SERVER["REMOTE_ADDR"]</code>.</li>'."\n"; |
| 1641 |
echo '<li><code>%%item_number%%</code> = The Item Number. Ex: <code><em>sp:13,24,36:72</em></code> (translates to: <code><em>sp:comma-delimited IDs:expiration hours</em></code>).</li>'."\n"; |
| 1642 |
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"; |
| 1643 |
echo '</ul>'."\n"; |
| 1644 |
|
| 1645 |
echo '<strong>Custom Replacement Codes can also be inserted using these instructions:</strong>'."\n"; |
| 1646 |
echo '<ul class="ws-menu-page-li-margins">'."\n"; |
| 1647 |
echo '<li><code>%%cv0%%</code> = The domain of your site, which is passed through the `custom` attribute in your Shortcode.</li>'."\n"; |
| 1648 |
echo '<li><code>%%cv1%%</code> = If you need to track additional custom variables, you can pipe delimit them into the `custom` attribute; inside your Shortcode, like this: <code>custom="'.esc_html($_SERVER["HTTP_HOST"]).'|cv1|cv2|cv3"</code>. You can have an unlimited number of custom variables. Obviously, this is for advanced webmasters; but the functionality has been made available for those who need it.</li>'."\n"; |
| 1649 |
echo '</ul>'."\n"; |
| 1650 |
echo '<strong>This example uses cv1 to record a special marketing campaign:</strong><br />'."\n"; |
| 1651 |
echo '<em>(The campaign (i.e., christmas-promo) could be referenced using <code>%%cv1%%</code>)</em><br />'."\n"; |
| 1652 |
echo '<code>custom="'.esc_html($_SERVER["HTTP_HOST"]).'|christmas-promo"</code>'."\n"; |
| 1653 |
|
| 1654 |
echo (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) ? |
| 1655 |
'<div class="ws-menu-page-hr"></div>'."\n". |
| 1656 |
'<p style="margin:0;"><strong>Advanced Customization:</strong> Further customization is possible with the <code>ws_plugin__s2member_sp_email_sbj</code> and <code>ws_plugin__s2member_sp_email_msg</code> filters from a plugin or theme.</p>'."\n" |
| 1657 |
: ''; |
| 1658 |
echo '</td>'."\n"; |
| 1659 |
|
| 1660 |
echo '</tr>'."\n"; |
| 1661 |
echo '</tbody>'."\n"; |
| 1662 |
echo '</table>'."\n"; |
| 1663 |
echo '</div>'."\n"; |
| 1664 |
|
| 1665 |
echo '</div>'."\n"; |
| 1666 |
|
| 1667 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_after_sp_confirmation_email", get_defined_vars()); |
| 1668 |
} |
| 1669 |
|
| 1670 |
if(apply_filters("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_display_eot_behavior", TRUE, get_defined_vars())) |
| 1671 |
{ |
| 1672 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_before_eot_behavior", get_defined_vars()); |
| 1673 |
|
| 1674 |
//260908.2031 Allow diagnostic/admin-notice links to open this collapsed panel before the shared menu-page JavaScript scrolls to a setting inside it. |
| 1675 |
echo '<div class="ws-menu-page-group" title="Automatic End-of-Term Behavior"'.((!empty($_GET['s2member-open-panel']) && $_GET['s2member-open-panel'] === 'auto-eot') ? ' default-state="open"' : '').'>'."\n"; |
| 1676 |
|
| 1677 |
echo '<div class="ws-menu-page-section ws-plugin--s2member-eot-behavior-section">'."\n"; |
| 1678 |
echo '<h3>PayPal End-of-Term Behavior (required, please choose)</h3>'."\n"; |
| 1679 |
echo '<p>EOT = End Of Term. By default, s2Member will demote a paid Member to the role selected under Demote To Role whenever their Subscription term has ended (i.e., expired), been cancelled, refunded, charged back to you, etc. s2Member assigns the role selected under Demote To Role; resulting access depends on that role and on any unrelated WordPress roles you choose to preserve. However, in some cases, you may prefer to have Customer accounts moved to Pending Deletion for administrator review, 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"; |
| 1680 |
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 & 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 assigned the role selected under Demote To Role, or have the configured Delete behavior applied automatically. The communication from PayPal → s2Member is seamless.</p>'."\n"; |
| 1681 |
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 process the membership EOT when an EOT (End Of Term) is reached, a refund occurs, a chargeback occurs, or when a cancellation later results in a delayed Auto-EOT by s2Member.</em></p>'."\n"; |
| 1682 |
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 process their membership EOT by either assigning the role selected under Demote To Role or applying the configured Delete behavior. 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"; |
| 1683 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_during_eot_behavior", get_defined_vars()); |
| 1684 |
|
| 1685 |
//260820.0306 Show current processing health where Auto-EOT is configured, so pending/stalled work is visible before it becomes a support issue. |
| 1686 |
$auto_eot_health = c_ws_plugin__s2member_auto_eots::auto_eot_system_health(TRUE); |
| 1687 |
$auto_eot_legacy_cap = c_ws_plugin__s2member_auto_eots::auto_eot_system_legacy_cap_info(); |
| 1688 |
$auto_eot_mode = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["auto_eot_system_enabled"]; |
| 1689 |
$auto_eot_runtime_target = c_ws_plugin__s2member_auto_eots::auto_eot_system_runtime_budget($auto_eot_mode === '2'); |
| 1690 |
$php_execution_limit = (int)ini_get('max_execution_time'); |
| 1691 |
$auto_eot_status_labels = array('healthy' => 'Healthy', 'processing' => 'Processing', 'catching_up' => 'Catching up', 'attention' => 'Attention', 'error' => 'Needs attention', 'disabled' => 'Disabled'); |
| 1692 |
$auto_eot_status_label = isset($auto_eot_status_labels[$auto_eot_health['status']]) ? $auto_eot_status_labels[$auto_eot_health['status']] : ucfirst($auto_eot_health['status']); |
| 1693 |
|
| 1694 |
$auto_eot_next_run = 0; |
| 1695 |
if($auto_eot_mode === '1') |
| 1696 |
{ |
| 1697 |
$_scheduled = array_filter(array((int)$auto_eot_health['recurring_at'], (int)$auto_eot_health['continuation_at'])); |
| 1698 |
$auto_eot_next_run = $_scheduled ? min($_scheduled) : 0; |
| 1699 |
unset($_scheduled); |
| 1700 |
} |
| 1701 |
|
| 1702 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 1703 |
echo '<h3>Automatic Behavior Status: <span class="ws-plugin--s2member-status-light ws-plugin--s2member-status-light-'.esc_attr($auto_eot_health['status']).'" aria-hidden="true"></span>'.esc_html($auto_eot_status_label).'</h3>'."\n"; |
| 1704 |
echo '<table class="ws-plugin--s2member-status-table"><tbody>'."\n"; |
| 1705 |
echo '<tr><th scope="row">Pending overdue EOTs:</th><td>'.number_format_i18n((int)$auto_eot_health['pending_count']).'</td></tr>'."\n"; |
| 1706 |
echo '<tr><th scope="row">Oldest overdue EOT:</th><td>'.($auto_eot_health['oldest_due_at'] ? esc_html(human_time_diff((int)$auto_eot_health['oldest_due_at'], time()).' ago') : 'None').'</td></tr>'."\n"; |
| 1707 |
echo '<tr><th scope="row">Last completed run:</th><td>'.($auto_eot_health['last_completed_at'] ? esc_html(human_time_diff((int)$auto_eot_health['last_completed_at'], time()).' ago') : 'Not recorded yet').'</td></tr>'."\n"; |
| 1708 |
echo '<tr><th scope="row">Last run:</th><td>'.($auto_eot_health['last_completed_at'] ? number_format_i18n((int)$auto_eot_health['last_processed']).' EOT(s) in '.esc_html(number_format_i18n((float)$auto_eot_health['last_runtime'], 2)).' seconds' : 'Not recorded yet').'</td></tr>'."\n"; |
| 1709 |
echo '<tr><th scope="row">Next run:</th><td>'.($auto_eot_mode === '1' ? ($auto_eot_next_run ? esc_html(($auto_eot_next_run <= time() ? human_time_diff($auto_eot_next_run, time()).' overdue' : 'in '.human_time_diff(time(), $auto_eot_next_run))) : 'Not scheduled') : ($auto_eot_mode === '2' ? 'Controlled by your external cron service' : 'Disabled')).'</td></tr>'."\n"; |
| 1710 |
echo '<tr><th scope="row">Current runtime target:</th><td>About '.esc_html(number_format_i18n($auto_eot_runtime_target, 0)).' seconds'.($php_execution_limit > 0 ? ' (PHP limit: '.esc_html($php_execution_limit).')' : ' (no set PHP limit)').'</td></tr>'."\n"; |
| 1711 |
//260828.0231 Keep current EOT work and previous EOT history separate while retaining WordPress' native Users table, filters, bulk actions, and Screen Options. |
| 1712 |
echo '<tr><th scope="row">End-of-Term users:</th><td><a href="'.esc_url(admin_url('/users.php?s2member_view=eot_current')).'">Current</a> | <a href="'.esc_url(admin_url('/users.php?s2member_view=eot_previous')).'">Previous</a></td></tr>'."\n"; |
| 1713 |
echo '</tbody></table>'."\n"; |
| 1714 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 1715 |
|
| 1716 |
//260820.0306 Legacy filters remain authoritative for compatibility, but explain when an inherited fixed-batch limit can now reduce adaptive throughput. |
| 1717 |
if(!empty($auto_eot_legacy_cap['detected'])) |
| 1718 |
{ |
| 1719 |
echo '<div class="ws-menu-page-notice ws-menu-page-notice-info">'."\n"; |
| 1720 |
echo '<p><strong>Legacy processing limit detected.</strong> A developer customization is using <code>ws_plugin__s2member_auto_eot_system_per_process</code>. This filter was useful with s2Member\'s older fixed-batch processor, but the new runtime-adaptive engine can usually process more efficiently without it. Unless it exists for a specific site reason, this legacy limit is probably unhelpful now.</p>'."\n"; |
| 1721 |
|
| 1722 |
if($auto_eot_legacy_cap['last_hard_cap_source'] === 'filter' && $auto_eot_legacy_cap['last_hard_cap'] !== NULL) |
| 1723 |
echo '<p>Last effective legacy limit: <strong>'.number_format_i18n((int)$auto_eot_legacy_cap['last_hard_cap']).' EOT(s) per pass</strong>.</p>'."\n"; |
| 1724 |
|
| 1725 |
if($auto_eot_legacy_cap['last_hard_cap_source'] === 'filter' && $auto_eot_legacy_cap['last_stop_reason'] === 'legacy_item_cap' && $auto_eot_legacy_cap['estimated_additional'] > 0) |
| 1726 |
echo '<p>On the last constrained run, s2Member estimates that approximately <strong>'.number_format_i18n((int)$auto_eot_legacy_cap['estimated_additional']).' additional EOT(s)</strong> could have fit within the remaining safe runtime without this hard limit.</p>'."\n"; |
| 1727 |
|
| 1728 |
if(!empty($auto_eot_legacy_cap['sources'])) |
| 1729 |
{ |
| 1730 |
echo '<p><strong>Detected source'.(count($auto_eot_legacy_cap['sources']) === 1 ? '' : 's').':</strong><br />'."\n"; |
| 1731 |
foreach($auto_eot_legacy_cap['sources'] as $_source) |
| 1732 |
{ |
| 1733 |
$_source_location = !empty($_source['file']) ? $_source['file'].(!empty($_source['line']) ? ':'.(int)$_source['line'] : '') : (!empty($_source['callback']) ? $_source['callback'] : 'Unknown callback'); |
| 1734 |
echo '<code>'.esc_html($_source_location).'</code><br />'."\n"; |
| 1735 |
} |
| 1736 |
echo '</p>'."\n"; |
| 1737 |
unset($_source, $_source_location); |
| 1738 |
} |
| 1739 |
echo '</div>'."\n"; |
| 1740 |
} |
| 1741 |
|
| 1742 |
echo '<p id="ws-plugin--s2member-auto-eot-system-enabled-via-cron"'.(($auto_eot_mode === '2') ? '' : ' style="display:none;"').'>If you\'d like to run s2Member\'s Auto-EOT System through a traditional Cron Job instead of WP-Cron, configure an HTTP Cron Job through your hosting/server control panel. Running it every <code>1 to 10 minutes</code> works well; about every <code>5 minutes</code> is a good default. Load this URL:<br /><code>'.esc_html(home_url("/?s2member_auto_eot_system_via_cron=1")).'</code></p>'."\n"; |
| 1743 |
|
| 1744 |
echo '<table class="form-table">'."\n"; |
| 1745 |
echo '<tbody>'."\n"; |
| 1746 |
echo '<tr>'."\n"; |
| 1747 |
|
| 1748 |
echo '<th>'."\n"; |
| 1749 |
echo '<label for="ws-plugin--s2member-auto-eot-system-enabled">'."\n"; |
| 1750 |
echo 'Enable s2Member\'s Auto-EOT System?'."\n"; |
| 1751 |
echo '</label>'."\n"; |
| 1752 |
echo '</th>'."\n"; |
| 1753 |
|
| 1754 |
echo '</tr>'."\n"; |
| 1755 |
echo '<tr>'."\n"; |
| 1756 |
|
| 1757 |
echo '<td>'."\n"; |
| 1758 |
echo '<select name="ws_plugin__s2member_auto_eot_system_enabled" id="ws-plugin--s2member-auto-eot-system-enabled">'."\n"; |
| 1759 |
//260820.0306 Health warnings now report scheduler problems explicitly, so always show the saved mode instead of blanking this field when cron is unhealthy. |
| 1760 |
echo '<option value="1"'.(($auto_eot_mode === '1') ? ' selected="selected"' : '').'>Yes (enable the Auto-EOT System through WP-Cron)</option>'."\n"; |
| 1761 |
echo (!is_multisite() || !c_ws_plugin__s2member_utils_conds::is_multisite_farm() || is_main_site()) ? '<option value="2"'.(($auto_eot_mode === '2') ? ' selected="selected"' : '').'>Yes (but, I\'ll run it with my own Cron Job)</option>'."\n" : ''; |
| 1762 |
echo '<option value="0"'.(($auto_eot_mode === '0') ? ' selected="selected"' : '').'>No (disable the Auto-EOT System)</option>'."\n"; |
| 1763 |
echo '</select><br />'."\n"; |
| 1764 |
echo 'Recommended setting: (<code>Yes / enable via WP-Cron</code>)'."\n"; |
| 1765 |
echo '<br /><em>When disabled, automatic End-of-Term processing is paused. s2Member can still record End-of-Term dates, and s2Member Pro reminders based on stored End-of-Term dates can continue independently. Overdue End-of-Term actions remain pending and will be processed if the Auto-EOT System is enabled again.</em>'."\n"; |
| 1766 |
echo '</td>'."\n"; |
| 1767 |
|
| 1768 |
echo '</tr>'."\n"; |
| 1769 |
echo '</tbody>'."\n"; |
| 1770 |
echo '</table>'."\n"; |
| 1771 |
|
| 1772 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 1773 |
|
| 1774 |
echo '<table class="form-table">'."\n"; |
| 1775 |
echo '<tbody>'."\n"; |
| 1776 |
echo '<tr>'."\n"; |
| 1777 |
echo '<th><label for="ws-plugin--s2member-auto-eot-system-runtime-mode">Auto-EOT Processing Runtime</label></th>'."\n"; |
| 1778 |
echo '</tr>'."\n"; |
| 1779 |
echo '<tr>'."\n"; |
| 1780 |
echo '<td>'."\n"; |
| 1781 |
echo '<select name="ws_plugin__s2member_auto_eot_system_runtime_mode" id="ws-plugin--s2member-auto-eot-system-runtime-mode">'."\n"; |
| 1782 |
echo '<option value="auto"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["auto_eot_system_runtime_mode"] === 'auto') ? ' selected="selected"' : '').'>Automatic (recommended)</option>'."\n"; |
| 1783 |
echo '<option value="custom"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["auto_eot_system_runtime_mode"] === 'custom') ? ' selected="selected"' : '').'>Custom maximum runtime</option>'."\n"; |
| 1784 |
echo '</select><br />'."\n"; |
| 1785 |
echo '<em>Automatic mode adapts the number of EOTs processed to the wall-clock time available in each run. The current target for this configuration is approximately <strong>'.esc_html(number_format_i18n($auto_eot_runtime_target, 1)).' seconds</strong>; it automatically leaves additional headroom below a finite PHP execution limit.</em>'."\n"; |
| 1786 |
echo '</td>'."\n"; |
| 1787 |
echo '</tr>'."\n"; |
| 1788 |
echo '<tr>'."\n"; |
| 1789 |
echo '<th><label for="ws-plugin--s2member-auto-eot-system-runtime-custom">Custom Maximum Runtime (seconds)</label></th>'."\n"; |
| 1790 |
echo '</tr>'."\n"; |
| 1791 |
echo '<tr>'."\n"; |
| 1792 |
echo '<td>'."\n"; |
| 1793 |
echo '<input type="number" min="1" max="3600" step="1" name="ws_plugin__s2member_auto_eot_system_runtime_custom" id="ws-plugin--s2member-auto-eot-system-runtime-custom" value="'.esc_attr($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["auto_eot_system_runtime_custom"]).'" /><br />'."\n"; |
| 1794 |
echo '<em>Used only in Custom mode. If PHP reports a finite execution limit, s2Member uses the lower of this value and 90% of PHP\'s limit. For example, if you enter 100 seconds and PHP\'s limit is 30 seconds, s2Member uses 27 seconds. Developers can still override the final runtime with <code>ws_plugin__s2member_auto_eot_system_runtime</code>.</em>'."\n"; |
| 1795 |
echo '</td>'."\n"; |
| 1796 |
echo '</tr>'."\n"; |
| 1797 |
echo '</tbody>'."\n"; |
| 1798 |
echo '</table>'."\n"; |
| 1799 |
|
| 1800 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 1801 |
|
| 1802 |
echo '<table class="form-table">'."\n"; |
| 1803 |
echo '<tbody>'."\n"; |
| 1804 |
echo '<tr>'."\n"; |
| 1805 |
|
| 1806 |
echo '<th>'."\n"; |
| 1807 |
echo '<label for="ws-plugin--s2member-membership-eot-behavior">'."\n"; |
| 1808 |
echo 'Membership End-of-Term Behavior (Demote or Delete)?'."\n"; |
| 1809 |
echo '</label>'."\n"; |
| 1810 |
echo '</th>'."\n"; |
| 1811 |
|
| 1812 |
echo '</tr>'."\n"; |
| 1813 |
echo '<tr>'."\n"; |
| 1814 |
|
| 1815 |
echo '<td>'."\n"; |
| 1816 |
echo '<select name="ws_plugin__s2member_membership_eot_behavior" id="ws-plugin--s2member-membership-eot-behavior">'."\n"; |
| 1817 |
echo '<option value="demote"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_eot_behavior"] === "demote") ? ' selected="selected"' : '').'>Demote (assign the role selected under Demote To Role)</option>'."\n"; |
| 1818 |
echo '<option value="delete"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["membership_eot_behavior"] === "delete") ? ' selected="selected"' : '').'>Delete (move to Pending Deletion for review)</option>'."\n"; |
| 1819 |
echo '</select><br />'."\n"; |
| 1820 |
//260822.0614 Keep the stored `delete` value for compatibility; irreversible deletion is an explicit developer opt-in rather than the product default. |
| 1821 |
echo '<em>Delete removes s2Member membership access and moves the account to the <strong>Pending Deletion</strong> role for administrator review. To restore historical automatic irreversible deletion, a developer must explicitly allow it with the <code>ws_plugin__s2member_allow_eot_user_deletion</code> filter.</em>'."\n"; |
| 1822 |
echo '</td>'."\n"; |
| 1823 |
|
| 1824 |
echo '</tr>'."\n"; |
| 1825 |
|
| 1826 |
//260916.1840 Keep the global EOT role destination/scope controls identical across every gateway page. |
| 1827 |
c_ws_plugin__s2member_menu_pages::eot_demotion_options(); |
| 1828 |
|
| 1829 |
echo '<tr>'."\n"; |
| 1830 |
|
| 1831 |
echo '<th>'."\n"; |
| 1832 |
echo '<label for="ws-plugin--s2member-eots-remove-ccaps">'."\n"; |
| 1833 |
echo 'Membership EOTs also Remove all Custom Capabilities?'."\n"; |
| 1834 |
echo '</label>'."\n"; |
| 1835 |
echo '</th>'."\n"; |
| 1836 |
|
| 1837 |
echo '</tr>'."\n"; |
| 1838 |
echo '<tr>'."\n"; |
| 1839 |
|
| 1840 |
echo '<td>'."\n"; |
| 1841 |
echo '<select name="ws_plugin__s2member_eots_remove_ccaps" id="ws-plugin--s2member-eots-remove-ccaps">'."\n"; |
| 1842 |
echo '<option value="1"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eots_remove_ccaps"]) ? ' selected="selected"' : '').'>Yes (an EOT also results in the loss of any Custom Capabilities a User/Member may have)</option>'."\n"; |
| 1843 |
echo '<option value="0"'.((!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eots_remove_ccaps"]) ? ' selected="selected"' : '').'>No (an EOT has no impact on any Custom Capabilities a User/Member may have)</option>'."\n"; |
| 1844 |
echo '</select><br />'."\n"; |
| 1845 |
echo '<em>NOTE: If Refunds/Reversals trigger an Immediate EOT (see setting below); Custom Capabilities will always be removed when/if a Refund or Reversal occurs. In other words, this setting is ignored for Refunds/Reversals (IF they trigger an Immediate EOT—based on your configuration below). If you prefer to review all Refunds/Reversals for yourself, please choose that option below.</em>'."\n"; |
| 1846 |
echo '</td>'."\n"; |
| 1847 |
|
| 1848 |
echo '</tr>'."\n"; |
| 1849 |
echo '</tbody>'."\n"; |
| 1850 |
echo '</table>'."\n"; |
| 1851 |
|
| 1852 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 1853 |
|
| 1854 |
echo '<table class="form-table">'."\n"; |
| 1855 |
echo '<tbody>'."\n"; |
| 1856 |
echo '<tr>'."\n"; |
| 1857 |
|
| 1858 |
echo '<th>'."\n"; |
| 1859 |
echo '<label for="ws-plugin--s2member-eot-grace-time">'."\n"; |
| 1860 |
echo 'EOT Grace Time (in seconds):'."\n"; |
| 1861 |
echo '</label>'."\n"; |
| 1862 |
echo '</th>'."\n"; |
| 1863 |
|
| 1864 |
echo '</tr>'."\n"; |
| 1865 |
echo '<tr>'."\n"; |
| 1866 |
|
| 1867 |
echo '<td>'."\n"; |
| 1868 |
echo '<input type="text" autocomplete="off" name="ws_plugin__s2member_eot_grace_time" id="ws-plugin--s2member-eot-grace-time" value="'.format_to_edit($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_grace_time"]).'" /><br />'."\n"; |
| 1869 |
echo '<em>This is represented in seconds. For example, a value of: <code>86400</code> = 1 day. Your EOT Grace Time; is the amount of time you will offer as a grace period (if any). Most site owners will give customers an additional 24 hours of access; just to help avoid any negativity that may result from a customer losing access sooner than they might expect. You can disable EOT Grace Time by setting this to: <code>0</code>. Note: there is NO Grace Time applied when/if a Refund or Reversal occurs. If Refunds/Reversals trigger an Immediate EOT (see setting below); there is never any Grace Time applied in that scenario.</em>'."\n"; |
| 1870 |
echo '</td>'."\n"; |
| 1871 |
|
| 1872 |
echo '</tr>'."\n"; |
| 1873 |
echo '</tbody>'."\n"; |
| 1874 |
echo '</table>'."\n"; |
| 1875 |
|
| 1876 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 1877 |
|
| 1878 |
echo '<table class="form-table">'."\n"; |
| 1879 |
echo '<tbody>'."\n"; |
| 1880 |
echo '<tr>'."\n"; |
| 1881 |
|
| 1882 |
echo '<th>'."\n"; |
| 1883 |
//260824.1957 Clarify that disputes/chargebacks are normalized into the existing Reversals policy without changing stored option values. |
| 1884 |
echo '<label for="ws-plugin--s2member-triggers-immediate-eot">'."\n"; |
| 1885 |
echo 'Refunds/Partial Refunds/Reversals/Disputes (trigger Immediate EOT)?'."\n"; |
| 1886 |
echo '</label>'."\n"; |
| 1887 |
echo '</th>'."\n"; |
| 1888 |
|
| 1889 |
echo '</tr>'."\n"; |
| 1890 |
echo '<tr>'."\n"; |
| 1891 |
|
| 1892 |
echo '<td>'."\n"; |
| 1893 |
echo '<select name="ws_plugin__s2member_triggers_immediate_eot" id="ws-plugin--s2member-triggers-immediate-eot">'."\n"; |
| 1894 |
echo '<option value="none"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["triggers_immediate_eot"] === "none") ? ' selected="selected"' : '').'>None (I\'ll review these events manually)</option>'."\n"; |
| 1895 |
echo '<option value="refunds"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["triggers_immediate_eot"] === "refunds") ? ' selected="selected"' : '').'>Full Refunds (full refunds only; ALWAYS trigger an Immediate EOT action)</option>'."\n"; |
| 1896 |
echo '<option value="reversals"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["triggers_immediate_eot"] === "reversals") ? ' selected="selected"' : '').'>Reversals/Disputes (including chargebacks; ALWAYS trigger an Immediate EOT action)</option>'."\n"; |
| 1897 |
echo '<option value="refunds,reversals"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["triggers_immediate_eot"] === "refunds,reversals") ? ' selected="selected"' : '').'>Full Refunds, Reversals/Disputes (these ALWAYS trigger an Immediate EOT action)</option>'."\n"; |
| 1898 |
echo '<option value="refunds,partial_refunds,reversals"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["triggers_immediate_eot"] === "refunds,partial_refunds,reversals") ? ' selected="selected"' : '').'>Full Refunds, Partial Refunds, Reversals/Disputes (these ALWAYS trigger an Immediate EOT action)</option>'."\n"; |
| 1899 |
echo '</select><br />'."\n"; |
| 1900 |
echo '<em><strong>Disputes/Chargebacks:</strong> When a supported gateway reports a dispute or chargeback, s2Member treats it as a Reversal for this setting. <strong>Note:</strong> s2Member is not equipped to detect partial refunds against multi-payment Subscriptions reliably. Therefore, all refunds processed against Subscriptions (of any kind) are considered <strong>Partial</strong> Refunds. Full refunds (in the eyes of s2Member) occur only against Buy Now transactions where it is easy for s2Member to see that the refund amount is >= the original Buy Now purchase price (i.e., a Full Refund). <strong>Also Note:</strong> This setting (no matter what you choose) will NOT impact s2Member\'s internal API Notifications for Refund/Reversal events. <a href="#" onclick="alert(\'A Full or Partial Refund; and/or a Reversal Notification will ALWAYS be processed internally by s2Member, even if no action is taken by s2Member in accordance with your configuration here.\\n\\nIn this way, you\\\'ll have the full ability to listen for these events on your own (via API Notifications); if you prefer (optional). For more information, check your Dashboard under: `s2Member → API Notifications → Refunds/Reversals`.\'); return false;">Click here for details</a>.</em>'."\n"; |
| 1901 |
echo '</td>'."\n"; |
| 1902 |
|
| 1903 |
echo '</tr>'."\n"; |
| 1904 |
echo '</tbody>'."\n"; |
| 1905 |
echo '</table>'."\n"; |
| 1906 |
|
| 1907 |
echo '<div class="ws-menu-page-hr"></div>'."\n"; |
| 1908 |
|
| 1909 |
echo '<table class="form-table">'."\n"; |
| 1910 |
echo '<tbody>'."\n"; |
| 1911 |
echo '<tr>'."\n"; |
| 1912 |
|
| 1913 |
echo '<th>'."\n"; |
| 1914 |
echo '<label for="ws-plugin--s2member-eot-time-ext-behavior">'."\n"; |
| 1915 |
echo 'Fixed-Term Extensions (Auto-Extend)?'."\n"; |
| 1916 |
echo '</label>'."\n"; |
| 1917 |
echo '</th>'."\n"; |
| 1918 |
|
| 1919 |
echo '</tr>'."\n"; |
| 1920 |
echo '<tr>'."\n"; |
| 1921 |
|
| 1922 |
echo '<td>'."\n"; |
| 1923 |
echo '<select name="ws_plugin__s2member_eot_time_ext_behavior" id="ws-plugin--s2member-eot-time-ext-behavior">'."\n"; |
| 1924 |
echo '<option value="extend"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_time_ext_behavior"] === "extend") ? ' selected="selected"' : '').'>Yes (default, automatically extend any existing EOT Time)</option>'."\n"; |
| 1925 |
echo '<option value="reset"'.(($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["eot_time_ext_behavior"] === "reset") ? ' selected="selected"' : '').'>No (do NOT extend; s2Member should reset EOT Time completely)</option>'."\n"; |
| 1926 |
echo '</select><br />'."\n"; |
| 1927 |
echo '<em>This setting will only affect Buy Now transactions for fixed-term lengths. By default, s2Member will automatically extend any existing EOT Time that a Customer may have. For example, if I buy one year of access, and then I buy another year of access (before my first year is totally used up); I end up with everything I paid you for (now over 1 year of access) if this is set to <code>Yes</code>. If this was set to <code>No</code>, the EOT Time would be reset when I make the second purchase; leaving me with only 1 year of access, starting the date of my second purchase.</em>'."\n"; |
| 1928 |
echo '</td>'."\n"; |
| 1929 |
|
| 1930 |
echo '</tr>'."\n"; |
| 1931 |
echo '</tbody>'."\n"; |
| 1932 |
echo '</table>'."\n"; |
| 1933 |
echo '</div>'."\n"; |
| 1934 |
|
| 1935 |
echo '</div>'."\n"; |
| 1936 |
|
| 1937 |
do_action("ws_plugin__s2member_during_paypal_ops_page_during_left_sections_after_eot_behavior", get_defined_vars()); |
| 1938 |
} |
| 1939 |
|
| 1940 |
do_action("ws_plugin__s2member_during_paypal_ops_page_after_left_sections", get_defined_vars()); |
| 1941 |
|
| 1942 |
echo '<p class="submit"><input type="submit" value="Save All Changes" /></p>'."\n"; |
| 1943 |
|
| 1944 |
echo '</form>'."\n"; |
| 1945 |
|
| 1946 |
echo '</td>'."\n"; |
| 1947 |
|
| 1948 |
echo '<td class="ws-menu-page-table-r">'."\n"; |
| 1949 |
c_ws_plugin__s2member_menu_pages_rs::display(); |
| 1950 |
echo '</td>'."\n"; |
| 1951 |
|
| 1952 |
echo '</tr>'."\n"; |
| 1953 |
echo '</tbody>'."\n"; |
| 1954 |
echo '</table>'."\n"; |
| 1955 |
|
| 1956 |
echo '</div>'."\n"; |
| 1957 |
} |
| 1958 |
} |
| 1959 |
} |
| 1960 |
|
| 1961 |
new c_ws_plugin__s2member_menu_page_paypal_ops(); |
| 1962 |
|