PluginProbe
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions / 261001
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions v261001
261001 260927 260917 260913 260909 260829 260814 260805 110710 110731 110812 110815 110912 110913 110915 110926 110927 111002 111003 111011 111017 111029 111105 111206 111216 All 191 releases
s2member / src / includes / classes / sc-paypal-button-in.inc.php

sc-paypal-button-in.inc.php in s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions 261001, at src/includes/classes/sc-paypal-button-in.inc.php

1,053 lines 92.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // @codingStandardsIgnoreFile
3 /**
4 * Shortcode `[s2Member-PayPal-Button]` (inner processing routines).
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\PayPal
16 * @since 3.5
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_sc_paypal_button_in"))
22 {
23 /**
24 * Shortcode `[s2Member-PayPal-Button]` (inner processing routines).
25 *
26 * @package s2Member\PayPal
27 * @since 3.5
28 */
29 class c_ws_plugin__s2member_sc_paypal_button_in
30 {
31 /**
32 * Handles the Shortcode for: `[s2Member-PayPal-Button /]`.
33 *
34 * @package s2Member\PayPal
35 * @since 3.5
36 *
37 * @attaches-to ``add_shortcode("s2Member-PayPal-Button");``
38 *
39 * @param array $attr An array of Attributes.
40 * @param string $content Content inside the Shortcode.
41 * @param string $shortcode The actual Shortcode name itself.
42 * @return string The resulting PayPal Button Code.
43 */
44 public static function sc_paypal_button ($attr = FALSE, $content = FALSE, $shortcode = FALSE)
45 {
46 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
47 do_action("ws_plugin__s2member_before_sc_paypal_button", get_defined_vars ());
48 unset($__refs, $__v);
49
50 c_ws_plugin__s2member_no_cache::no_cache_constants /* No caching on pages that contain this Payment Button. */ (true);
51
52 $attr = /* Force array. Trim quote entities. */ c_ws_plugin__s2member_utils_strings::trim_qts_deep ((array)$attr);
53
54 $attr = shortcode_atts (apply_filters("ws_plugin__s2member_sc_paypal_button_default_attrs", array("ids" => "0", "exp" => "72", "level" => "1", "ccaps" => "", "desc" => "", "ps" => "paypal", "lc" => "", "lang" => "", "cc" => "USD", "dg" => "0", "ns" => "1", "custom" => $_SERVER["HTTP_HOST"], "ta" => "0", "tp" => "0", "tt" => "D", "ra" => "0.01", "rp" => "1", "rt" => "M", "rr" => "1", "rrt" => "", "rra" => "1", "modify" => "0", "cancel" => "0", "sp" => "0", "image" => "default", "output" => "button"), get_defined_vars ()), $attr);
55
56 // "modify" has been deprecated. https://developer.paypal.com/docs/classic/paypal-payments-standard/integration-guide/Appx-websitestandard-htmlvariables/#deprecated-variables
57 $attr["modify"] = "0";
58
59 $attr["lc"] = /* Locale code absolutely must be provided in upper-case format. Only after running shortcode_atts(). */ strtoupper ($attr["lc"]);
60 $attr["tt"] = /* Term lengths absolutely must be provided in upper-case format. Only after running shortcode_atts(). */ strtoupper ($attr["tt"]);
61 $attr["rt"] = /* Term lengths absolutely must be provided in upper-case format. Only after running shortcode_atts(). */ strtoupper ($attr["rt"]);
62 $attr["rr"] = /* Must be provided in upper-case format. Numerical, or BN value. Only after running shortcode_atts(). */ strtoupper ($attr["rr"]);
63 $attr["ccaps"] = /* Custom Capabilities must be typed in lower-case format. Only after running shortcode_atts(). */ strtolower ($attr["ccaps"]);
64 $attr["ccaps"] = /* Custom Capabilities should not have spaces. */ str_replace(" ", "", $attr["ccaps"]);
65 $attr["rr"] = /* Lifetime Subscriptions require Buy Now. Only after running shortcode_atts(). */ ($attr["rt"] === "L") ? "BN" : $attr["rr"];
66 $attr["rr"] = /* Independent Ccaps require Buy Now. Only after running shortcode_atts(). */ ($attr["level"] === "*") ? "BN" : $attr["rr"];
67 $attr["ns"] = /* No shipping directive must be 1 for digital items. After shortcode_atts(). */ ($attr["dg"] === "1") ? "1" : $attr["ns"];
68 $attr["ta"] = /*260228 Normalize trial amount to canonical 2-decimal currency format. */ number_format((float)$attr["ta"], 2, '.', '');
69 $attr["ra"] = /*260228 Normalize recurring/regular amount to canonical 2-decimal currency format. */ number_format((float)$attr["ra"], 2, '.', '');
70
71 //260811 Sanitize custom image URL.
72 if($attr["image"] !== "default")
73 $attr["image"] = esc_url_raw($attr["image"], array('http', 'https'));
74
75 $force_notify_url_scheme = apply_filters("ws_plugin__s2member_during_sc_paypal_button_force_notify_url_scheme", null, get_defined_vars ());
76 $force_return_url_scheme = apply_filters("ws_plugin__s2member_during_sc_paypal_button_force_return_url_scheme", null, get_defined_vars ());
77
78 //260918.2104 TO-DO PayPal Checkout cache hardening: do not embed the one-hour, visitor-specific transaction token in rendered page HTML.
79 // Render a cache-safe encrypted checkout definition instead, then mint the short-lived invoice/IP/user-context transaction token server-side
80 // when checkout actually starts (output="button", "anchor", or "url"), preserving validation, idempotency, subscription context, and return/cancel behavior.
81
82 // PayPal Checkout SDK memoization (per request; shared across all button variants).
83 static $ppco_sdks = array();
84
85 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
86 do_action("ws_plugin__s2member_before_sc_paypal_button_after_shortcode_atts", get_defined_vars ());
87 unset($__refs, $__v);
88
89 if /* Cancellation Buttons. */ ($attr["cancel"])
90 {
91 //260114 PayPal Checkout (REST) cancellation override.
92 // - output="button": on-site cancel via REST API (logged-in users only).
93 // - output="anchor|url": link to PayPal subscription management UI (sandbox/live aware).
94 // Falls back to legacy PayPal cancellation flow when user is not logged in or has no subscription id.
95 if(c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_enabled() && in_array($attr["output"], array("button", "anchor", "url"), true) && is_user_logged_in())
96 {
97 $user_id = (int)get_current_user_id();
98 $subscr_id = (string)get_user_option('s2member_subscr_id', $user_id);
99
100 $ppco_sandbox = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_sandbox();
101 $pp_manage_url = ($ppco_sandbox) ? 'https://www.sandbox.paypal.com/myaccount/autopay/connect/' : 'https://www.paypal.com/myaccount/autopay/'; //260218
102
103 // output="url|anchor": always link to PayPal subscription management UI.
104 if(in_array($attr["output"], array("url", "anchor"), true))
105 {
106 // output="url": return the PayPal management URL.
107 if($attr["output"] === "url")
108 {
109 $code = $_code = $pp_manage_url;
110
111 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
112 do_action("ws_plugin__s2member_during_sc_paypal_cancellation_button", get_defined_vars ());
113 unset($__refs, $__v);
114
115 $code = c_ws_plugin__s2member_sc_paypal_button_e::sc_paypal_button_encryption ($code, get_defined_vars ());
116 return apply_filters("ws_plugin__s2member_sc_paypal_button", $code, get_defined_vars ());
117 }
118 // output="anchor": real anchor tag to PayPal management UI (no JS).
119 else if($attr["output"] === "anchor")
120 {
121 $default_image = "https://www.paypal.com/" . (($attr["lang"]) ? $attr["lang"] : _x ("en_US", "s2member-front paypal-button-lang-code", "s2member")) . "/i/btn/btn_unsubscribe_LG.gif";
122
123 if($attr["image"] && $attr["image"] !== "default")
124 {
125 $img_src = $attr["image"];
126 $code = $_code = '<a href="'.esc_attr($pp_manage_url).'" target="_blank" rel="nofollow noopener"><img src="'.esc_attr($img_src).'" style="width:auto; height:auto; border:0;" alt="PayPal" /></a>';
127 }
128 else
129 {
130 //260218 Match PayPal Checkout cancellation output="button" styling for output="anchor" (default image).
131 $ppco_cancel_label = esc_html(_x('Unsubscribe', 'paypal cancellation button label', 's2member'));
132 $ppco_a_id = 's2member_ppco_cancel_anchor_'.md5($user_id.$subscr_id);
133
134 $code = '<style type="text/css">a#'.esc_attr($ppco_a_id).'{display:inline-flex;align-items:center;justify-content:center;width:150px;height:40px;padding:10px 0;border-radius:4px;border:1px solid rgba(0,0,0,0.06);background:#ffc439 !important;color:#003087 !important;font-family:Helvetica, Arial, sans-serif;font-size:14px;font-weight:600;cursor:pointer;box-sizing:border-box;white-space:nowrap;text-decoration:none !important;} a#'.esc_attr($ppco_a_id).':link,a#'.esc_attr($ppco_a_id).':visited,a#'.esc_attr($ppco_a_id).':active{color:#003087 !important;background:#ffc439 !important;text-decoration:none !important;} a#'.esc_attr($ppco_a_id).':hover{color:#003087 !important;text-decoration:none !important;filter:brightness(0.98);}</style>'."\n";
135 $code .= '<a id="'.esc_attr($ppco_a_id).'" href="'.esc_attr($pp_manage_url).'" target="_blank" rel="nofollow noopener">'.$ppco_cancel_label.'</a>';
136 $_code = $code;
137 }
138
139 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
140 do_action("ws_plugin__s2member_during_sc_paypal_cancellation_button", get_defined_vars ());
141 unset($__refs, $__v);
142
143 $code = c_ws_plugin__s2member_sc_paypal_button_e::sc_paypal_button_encryption ($code, get_defined_vars ());
144 return apply_filters("ws_plugin__s2member_sc_paypal_button", $code, get_defined_vars ());
145 }
146 }
147
148 if($subscr_id)
149 {
150
151 // output="button": if Paid Subscr. ID is not a subscription id, fall back to PayPal management UI.
152 if($attr["output"] === "button" && !preg_match('/^I-[A-Z0-9]+$/', $subscr_id))
153 {
154 $default_image = "https://www.paypal.com/" . (($attr["lang"]) ? $attr["lang"] : _x ("en_US", "s2member-front paypal-button-lang-code", "s2member")) . "/i/btn/btn_unsubscribe_LG.gif";
155
156 if($attr["image"] && $attr["image"] !== "default")
157 {
158 $img_src = $attr["image"];
159 $code = $_code = '<a href="'.esc_attr($pp_manage_url).'" target="_blank" rel="nofollow noopener"><img src="'.esc_attr($img_src).'" style="width:auto; height:auto; border:0;" alt="PayPal" /></a>';
160 }
161 else
162 {
163 //260218 Match PayPal Checkout cancellation output="button" styling for fallback output="anchor" (default image).
164 $ppco_cancel_label = esc_html(_x('Unsubscribe', 'paypal cancellation button label', 's2member'));
165 $ppco_a_id = 's2member_ppco_cancel_anchor_'.md5($user_id.$subscr_id);
166
167 $code = '<style type="text/css">a#'.esc_attr($ppco_a_id).'{display:inline-flex;align-items:center;justify-content:center;width:150px;height:40px;padding:10px 0;border-radius:4px;border:1px solid rgba(0,0,0,0.06);background:#ffc439 !important;color:#003087 !important;font-family:Helvetica, Arial, sans-serif;font-size:14px;font-weight:600;cursor:pointer;box-sizing:border-box;white-space:nowrap;text-decoration:none !important;} a#'.esc_attr($ppco_a_id).':link,a#'.esc_attr($ppco_a_id).':visited,a#'.esc_attr($ppco_a_id).':active{color:#003087 !important;background:#ffc439 !important;text-decoration:none !important;} a#'.esc_attr($ppco_a_id).':hover{color:#003087 !important;text-decoration:none !important;filter:brightness(0.98);}</style>'."\n";
168 $code .= '<a id="'.esc_attr($ppco_a_id).'" href="'.esc_attr($pp_manage_url).'" target="_blank" rel="nofollow noopener">'.$ppco_cancel_label.'</a>';
169 $_code = $code;
170 }
171
172 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
173 do_action("ws_plugin__s2member_during_sc_paypal_cancellation_button", get_defined_vars ());
174 unset($__refs, $__v);
175
176 $code = c_ws_plugin__s2member_sc_paypal_button_e::sc_paypal_button_encryption ($code, get_defined_vars ());
177 return apply_filters("ws_plugin__s2member_sc_paypal_button", $code, get_defined_vars ());
178 }
179
180 // output="button": REST cancel (modern-looking HTML button).
181 $ppco_endpoint = home_url("/?s2member_paypal_checkout=1", $force_notify_url_scheme);
182
183 // Token must satisfy the standard token validator (invoice/ip/item_number/checksum).
184 $ppco_invoice = 'cancel-'.$user_id.'-'.$subscr_id;
185
186 $ppco_token = array(
187 'exp' => time() + 3600,
188 'invoice' => $ppco_invoice,
189 'ip' => c_ws_plugin__s2member_utils_ip::current(),
190 'item_number' => $subscr_id,
191 'checksum' => md5($ppco_invoice.c_ws_plugin__s2member_utils_ip::current().$subscr_id),
192
193 'user_id' => $user_id,
194 'subscr_id' => $subscr_id,
195 );
196
197 $ppco_token = urlencode(c_ws_plugin__s2member_utils_encryption::encrypt(serialize($ppco_token)));
198 $ppco_nonce = wp_create_nonce('s2m_ppco_cancel_'.$user_id);
199
200 $ppco_btn_id = 's2member_ppco_cancel_'.md5($user_id.$subscr_id);
201 $ppco_msg_id = 's2member_ppco_cancel_msg_'.md5($user_id.$subscr_id);
202
203 //260913.1946 Validate Pro's optional success URL before exposing it to cancellation JavaScript; shortcode attributes may be authored by Editors.
204 $ppco_success_url = (c_ws_plugin__s2member_utils_conds::pro_is_installed() && !empty($attr["success"]) && is_string($attr["success"])) ? wp_validate_redirect($attr["success"], '') : '';
205 $ppco_success_json = wp_json_encode($ppco_success_url, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
206
207 $code = '<style type="text/css">#'.esc_attr($ppco_btn_id).'{display:inline-flex;align-items:center;justify-content:center;width:150px;height:40px;padding:10px 0;border-radius:4px;border:1px solid rgba(0,0,0,0.06);background:#ffc439;color:#003087;font-family:Helvetica, Arial, sans-serif;font-size:14px;font-weight:600;cursor:pointer;box-sizing:border-box;white-space:nowrap;}#'.esc_attr($ppco_btn_id).':hover{filter:brightness(0.98);}#'.esc_attr($ppco_btn_id).':disabled{opacity:0.65;cursor:not-allowed;}</style>'."\n";
208 $code .= '<button type="button" id="'.esc_attr($ppco_btn_id).'">'.esc_html(_x('Unsubscribe', 'paypal cancellation button label', 's2member')).'</button>'."\n"; //260218
209 $code .= '<div id="'.esc_attr($ppco_msg_id).'" style="display:none; margin-top:8px;"></div>'."\n";
210 $code .= '<script type="text/javascript">'."\n";
211 $code .= '(function(){'."\n";
212 $code .= 'var b=document.getElementById("'.esc_js($ppco_btn_id).'");'."\n";
213 $code .= 'var m=document.getElementById("'.esc_js($ppco_msg_id).'");'."\n";
214 $code .= 'var u="'.esc_js($pp_manage_url).'";'."\n";
215 $code .= 'var s='.$ppco_success_json.';'."\n";
216 $code .= 'function goManage(){try{var w=window.open(u,"_blank","noopener");if(!w){window.location.href=u;}}catch(e){window.location.href=u;}}'."\n";
217 $code .= 'function show(msg){try{if(m){m.style.display="block";m.innerHTML=msg;}}catch(e){}}'."\n";
218 $code .= 'function enc(o){var s=[];for(var k in o){if(!o.hasOwnProperty(k))continue;s.push(encodeURIComponent(k)+"="+encodeURIComponent(o[k]));}return s.join("&");}'."\n";
219 $code .= 'if(!b){return;}'."\n";
220 $code .= 'b.addEventListener("click",function(e){'."\n";
221 $code .= 'e.preventDefault();'."\n";
222 $code .= 'if(b.disabled){return;}'."\n";
223 $code .= 'if(!window.confirm("'.esc_js(__('Cancel your subscription now?', 's2member')).'")){return;}'."\n"; //260218
224 $code .= 'b.disabled=true;'."\n";
225 $code .= 'fetch("'.esc_js($ppco_endpoint).'",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},body:enc({s2member_paypal_checkout_op:"cancel_subscription",s2member_paypal_checkout_t:"'.esc_js($ppco_token).'",s2member_paypal_checkout_nonce:"'.esc_js($ppco_nonce).'"} )})'."\n";
226 $code .= '.then(function(r){return r.json();})'."\n";
227 $code .= '.then(function(res){if(res&&res.ok){if(s){window.location.assign(s);}else{show("'.esc_js(__('Subscription cancelled.', 's2member')).'");}}else{goManage(); b.disabled=false;}})'."\n"; //260913.1946 Honor Pro's validated success URL after a confirmed on-site cancellation.
228 $code .= '.catch(function(){goManage(); b.disabled=false;});'."\n";
229 $code .= '});'."\n";
230 $code .= '})();'."\n";
231 $code .= '</script>'."\n";
232 $_code = $code;
233
234 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
235 do_action("ws_plugin__s2member_during_sc_paypal_cancellation_button", get_defined_vars ());
236 unset($__refs, $__v);
237
238 $code = c_ws_plugin__s2member_sc_paypal_button_e::sc_paypal_button_encryption ($code, get_defined_vars ());
239 return apply_filters("ws_plugin__s2member_sc_paypal_button", $code, get_defined_vars ());
240 }
241 }
242 else if(c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_enabled() && $attr["output"] === "button")
243 {
244 //260505 Guest output="button": show a disabled PayPal-styled button (no action). Guest output="anchor|url" falls through to the PayPal management link.
245 $ppco_btn_id = 's2member_ppco_cancel_disabled_'.md5((string)microtime(true));
246 $code = '<style type="text/css">#'.esc_attr($ppco_btn_id).'{display:inline-flex;align-items:center;justify-content:center;width:150px;height:40px;padding:10px 0;border-radius:4px;border:1px solid rgba(0,0,0,0.06);background:#ffc439;color:#003087;font-family:Helvetica, Arial, sans-serif;font-size:14px;font-weight:600;cursor:not-allowed;box-sizing:border-box;opacity:0.55;white-space:nowrap;}</style>'."\n";
247 $code .= '<button type="button" id="'.esc_attr($ppco_btn_id).'" disabled="disabled">'.esc_html(_x('Unsubscribe', 'paypal cancellation button label', 's2member')).'</button>'."\n"; //260218
248 $_code = $code;
249
250 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
251 do_action("ws_plugin__s2member_during_sc_paypal_cancellation_button", get_defined_vars ());
252 unset($__refs, $__v);
253
254 $code = c_ws_plugin__s2member_sc_paypal_button_e::sc_paypal_button_encryption ($code, get_defined_vars ());
255 return apply_filters("ws_plugin__s2member_sc_paypal_button", $code, get_defined_vars ());
256 }
257
258 $default_image = "https://www.paypal.com/" . (($attr["lang"]) ? $attr["lang"] : _x ("en_US", "s2member-front paypal-button-lang-code", "s2member")) . "/i/btn/btn_unsubscribe_LG.gif";
259
260 $code = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/paypal-cancellation-button.php")));
261 $code = preg_replace ("/%%images%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . "/src/images")), $code);
262 $code = preg_replace ("/%%wpurl%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr (home_url ())), $code);
263
264 $endpoint_host = ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com";
265 if(c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_enabled())
266 $endpoint_host = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_sandbox() ? "www.sandbox.paypal.com" : "www.paypal.com";
267
268 $autopay_url = (strpos($endpoint_host, 'sandbox') !== false)
269 ? "https://www.sandbox.paypal.com/myaccount/autopay/connect/"
270 : "https://www.paypal.com/myaccount/autopay/"; //260218
271
272 $code = preg_replace ("/%%autopay_url%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($autopay_url)), $code);
273 $code = preg_replace ("/%%paypal_business%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"])), $code);
274 $code = preg_replace ("/%%paypal_merchant_id%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_merchant_id"])), $code);
275
276 $code = $_code = ($attr["image"] && $attr["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["image"])) . '"', $code) : preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($default_image)) . '"', $code);
277
278 $code = ($attr["output"] === "anchor") ? /* Already in anchor format; `button` format is not used in Cancellations. */ $code : $code;
279 if ($attr["output"] === "url" && preg_match ('/ href\="(.*?)"/', $code, $m) && ($href = $m[1]))
280 $code = ($url = c_ws_plugin__s2member_utils_urls::n_amps ($href));
281
282 unset /* Just a little housekeeping */ ($href, $url, $m);
283
284 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
285 do_action("ws_plugin__s2member_during_sc_paypal_cancellation_button", get_defined_vars ());
286 unset($__refs, $__v);
287 }
288 else if /* Specific Post/Page Buttons. */ ($attr["sp"])
289 {
290 $default_image = "https://www.paypal.com/" . (($attr["lang"]) ? $attr["lang"] : _x ("en_US", "s2member-front paypal-button-lang-code", "s2member")) . "/i/btn/btn_xpressCheckout.gif";
291
292 $paypal_on0_input_value = ($referencing = c_ws_plugin__s2member_utils_users::get_user_subscr_or_wp_id ()) ? "Referencing Customer ID" : "Originating Domain";
293 $paypal_os0_input_value = /* Current User's Paid Subscr. ID, or WP User ID, or domain. */ ($referencing) ? $referencing : $_SERVER["HTTP_HOST"];
294
295 $paypal_on1_input_value = /* Identifies the Customer's IP Address for tracking purposes. */ "Customer IP Address";
296 $paypal_os1_input_value = /* Current User's IP Address for tracking purposes. */ c_ws_plugin__s2member_utils_ip::current();
297
298 $paypal_invoice_input_value = /* s2Member's Unique Code~IP combo. */ uniqid () . "~" . c_ws_plugin__s2member_utils_ip::current();
299
300 //260928.1515 Give each rendered PayPal Checkout button a signed provisional identity; persist its Gateway Checkout only when the buyer starts, never on page render.
301 $ppco_gateway_checkout_identity = FALSE;
302 if(c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_enabled())
303 {
304 $ppco_gateway_checkout_identity = c_ws_plugin__s2member_gateway_checkouts::browser_identity();
305 $paypal_invoice_input_value = 's2mb-'.(string)$ppco_gateway_checkout_identity['id'];
306 }
307
308 $attr["sp_ids_exp"] = /* Combined "sp:ids:expiration hours". */ "sp:" . $attr["ids"] . ":" . $attr["exp"];
309
310 $success_return_url = /* s2Member handles this all by itself. However, it can be Filtered. */ home_url ("/?s2member_paypal_return=1", $force_return_url_scheme);
311 $success_return_url = apply_filters("ws_plugin__s2member_during_sc_paypal_button_success_return_url", $success_return_url, get_defined_vars ());
312
313 //260114 PayPal Checkout (REST) SP (Specific Post/Page) override.
314 // Uses server-side create + server-side capture, then posts into existing IPN + Return handlers.
315 if(c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_enabled())
316 {
317 $ppco_sandbox = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_sandbox();
318 $ppco_client_id = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"][($ppco_sandbox) ? "paypal_checkout_sandbox_client_id" : "paypal_checkout_client_id"];
319
320 $ppco_cc = strtoupper((string)$attr["cc"]);
321 $ppco_intent = 'capture';
322
323 $ppco_sdk_key = (($ppco_sandbox) ? 'sandbox' : 'live').'|'.$ppco_cc.'|'.$ppco_intent;
324
325 $ppco_sdk_just_loaded = false;
326 if(empty($ppco_sdks[$ppco_sdk_key]) || !is_array($ppco_sdks[$ppco_sdk_key]))
327 {
328 $ppco_sdks[$ppco_sdk_key] = array(
329 'ns' => 's2m_ppco_'.substr(md5($ppco_sdk_key), 0, 10),
330 'id' => 's2member_ppco_sdk_'.substr(md5($ppco_sdk_key), 0, 10),
331 );
332 $ppco_sdk_just_loaded = true;
333 }
334
335 $ppco_sdk_ns = (string)$ppco_sdks[$ppco_sdk_key]['ns'];
336 $ppco_sdk_id = (string)$ppco_sdks[$ppco_sdk_key]['id'];
337
338 $ppco_endpoint = home_url("/?s2member_paypal_checkout=1", $force_notify_url_scheme);
339 $ppco_cancel = home_url("/");
340
341 $ppco_token = array(
342 'exp' => time() + 3600,
343
344 'invoice' => $paypal_invoice_input_value,
345 'ip' => c_ws_plugin__s2member_utils_ip::current(),
346 'item_name' => $attr["desc"],
347 'item_number' => $attr["sp_ids_exp"],
348 'custom' => $attr["custom"],
349
350 'amount' => $attr["ra"],
351 'cc' => $ppco_cc,
352 'ns' => $attr["ns"],
353
354 'rr' => 'BN',
355
356 'on0' => $paypal_on0_input_value,
357 'os0' => $paypal_os0_input_value,
358 'on1' => $paypal_on1_input_value,
359 'os1' => $paypal_os1_input_value,
360
361 'return' => $success_return_url,
362 'cancel' => $ppco_cancel,
363
364 'checksum' => md5($paypal_invoice_input_value.c_ws_plugin__s2member_utils_ip::current().$attr["sp_ids_exp"]),
365 );
366
367 //260928.1515 Bind the PayPal invoice and encrypted purchase terms to the same provisional Gateway Checkout identity, including in anchor/url mode.
368 if($ppco_gateway_checkout_identity)
369 {
370 $ppco_token['gateway_checkout_id'] = (string)$ppco_gateway_checkout_identity['id'];
371 $ppco_token['gateway_checkout_token'] = (string)$ppco_gateway_checkout_identity['token'];
372 }
373
374 $ppco_token = urlencode(c_ws_plugin__s2member_utils_encryption::encrypt(serialize($ppco_token)));
375
376 // output="anchor|url" support (no JS SDK; redirects through s2Member, then to PayPal approval URL).
377 if($attr["output"] === "anchor" || $attr["output"] === "url")
378 {
379 $ppco_redirect_url = $ppco_endpoint.'&s2member_paypal_checkout_op=redirect&s2member_paypal_checkout_t='.$ppco_token;
380
381 if($attr["output"] === "url")
382 $code = $_code = $ppco_redirect_url;
383
384 else // output="anchor"
385 {
386 $img_src = ($attr["image"] && $attr["image"] !== "default") ? $attr["image"] : $default_image;
387 $code = $_code = '<a class="ws-plugin--s2member-paypal-button ws-plugin--s2member-paypal-anchor" href="'.esc_attr($ppco_redirect_url).'"><img class="ws-plugin--s2member-paypal-button-img" src="'.esc_attr($img_src).'" style="width:auto; height:auto; border:0; margin:0;" alt="PayPal" /></a>';
388 }
389
390 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
391 do_action("ws_plugin__s2member_during_sc_paypal_sp_button", get_defined_vars ());
392 unset($__refs, $__v);
393
394 $code = c_ws_plugin__s2member_sc_paypal_button_e::sc_paypal_button_encryption ($code, get_defined_vars ());
395 return apply_filters("ws_plugin__s2member_sc_paypal_button", $code, get_defined_vars ());
396 }
397
398 $ppco_div_id = 's2member_ppco_btn_'.md5($paypal_invoice_input_value.$attr["sp_ids_exp"]);
399 $ppco_err_id = 's2member_ppco_err_'.md5($paypal_invoice_input_value.$attr["sp_ids_exp"]);
400
401 $ppco_locale = ($attr["lang"]) ? (string)$attr["lang"] : '';
402 $ppco_lc = ($attr["lc"]) ? (string)$attr["lc"] : '';
403
404 if(!$ppco_locale && $ppco_lc)
405 {
406 $site_locale = (string)get_locale();
407 if(preg_match('/^([a-z]{2})[_-]/i', $site_locale, $m))
408 $ppco_locale = strtolower($m[1]).'_'.strtoupper($ppco_lc);
409 else
410 $ppco_locale = 'en_'.strtoupper($ppco_lc);
411 }
412
413 $ppco_locale_q = ($ppco_locale) ? '&locale='.rawurlencode($ppco_locale) : '';
414 $ppco_buyer_country_q = ($ppco_sandbox && $ppco_lc) ? '&buyer-country='.rawurlencode(strtoupper($ppco_lc)) : '';
415
416 $ppco_sdk_src = ($ppco_sandbox ? 'https://www.sandbox.paypal.com/sdk/js' : 'https://www.paypal.com/sdk/js');
417 //260114 !!! SP is capture-only; conditional subscription path below is dead code (cleanup/refactor later).
418 if($ppco_intent === 'subscription')
419 $ppco_sdk_src = $ppco_sdk_src.'?client-id='.rawurlencode($ppco_client_id).'&currency='.rawurlencode($ppco_cc).'&vault=true&intent=subscription&disable-funding=card'.$ppco_buyer_country_q.$ppco_locale_q;
420 else
421 $ppco_sdk_src = $ppco_sdk_src.'?client-id='.rawurlencode($ppco_client_id).'&currency='.rawurlencode($ppco_cc).'&intent=capture&commit=true&disable-funding=card'.$ppco_buyer_country_q.$ppco_locale_q;
422
423 $code = '<div id="'.esc_attr($ppco_div_id).'" class="ws-plugin--s2member-paypal-button ws-plugin--s2member-ppco-button" style="max-width:145px; width:auto; margin:0;"></div>'."\n";
424 $code .= '<div id="'.esc_attr($ppco_err_id).'" class="ws-plugin--s2member-ppco-message" style="display:none; margin:0;"></div>'."\n";
425
426 $ppco_sdk_src = apply_filters('ws_plugin__s2member_ppco_sdk_src', $ppco_sdk_src, get_defined_vars());
427
428 if($ppco_sdk_just_loaded)
429 {
430 $code .= '<script id="'.esc_attr($ppco_sdk_id).'" data-namespace="'.esc_attr($ppco_sdk_ns).'" src="'.esc_attr($ppco_sdk_src).'"></script>'."\n";
431 }
432
433 $code .= '<script type="text/javascript">'."\n";
434 $code .= '(function(){'."\n";
435 $code .= 'var d="'.esc_js($ppco_div_id).'";'."\n";
436 $code .= 'var e="'.esc_js($ppco_err_id).'";'."\n";
437 $code .= 'var t="'.esc_js($ppco_token).'";'."\n";
438 $code .= 'var u="'.esc_js($ppco_endpoint).'";'."\n";
439 //260928.1739 Bind to the SDK script actually emitted above and encode its URL as JavaScript, not HTML entities.
440 $code .= 'var ns="'.esc_js($ppco_sdk_ns).'";'."\n";
441 $code .= 'var sdkId="'.esc_js($ppco_sdk_id).'";'."\n";
442 $code .= 'var s='.wp_json_encode($ppco_sdk_src, JSON_HEX_AMP | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT).';'."\n";
443 $code .= 'var cid="'.esc_js($paypal_invoice_input_value).'";'."\n";
444 //260819.0042 Keep standalone Checkout feedback consistent with Pro-Forms while distinguishing cancellation from errors.
445 $code .= 'function showMsg(m,t){try{var el=document.getElementById(e);if(el){el.style.display="block";el.innerHTML="<span class=\"ws-plugin--s2member-ppco-"+(t==="info"?"info":"error")+"\">"+m+"</span>";}}catch(x){}}function showErr(m){showMsg(m,"error");}function showInfo(m){showMsg(m,"info");}'."\n";
446 $code .= 'function postTo(url, data){var f=document.createElement("form");f.method="post";f.acceptCharset="UTF-8";f.action=url;for(var k in data){if(!data.hasOwnProperty(k))continue;var i=document.createElement("input");i.type="hidden";i.name=k;i.value=data[k];f.appendChild(i);}document.body.appendChild(f);f.submit();}'."\n"; //260817 Keep signed PayPal Checkout returns in UTF-8.
447 $code .= 'function enc(o){var a=[];for(var k in o){if(!o.hasOwnProperty(k))continue;a.push(encodeURIComponent(k)+"="+encodeURIComponent(o[k]));}return a.join("&");}'."\n";
448 $code .= 'function loadSdk(cb){var P=window[ns];if(P&&P.Buttons){cb(P);return;}var id=sdkId,tag=document.getElementById(id),done=false;function finish(){if(done)return;done=true;cb(window[ns]&&window[ns].Buttons?window[ns]:null);}function ok(){finish();}function fail(){finish();}if(tag){if(window[ns]&&window[ns].Buttons){finish();return;}if(tag.getAttribute("src")!==s){tag.setAttribute("src",s);}if(tag.readyState==="complete"||tag.readyState==="loaded"){setTimeout(finish,0);return;}tag.addEventListener("load",ok);tag.addEventListener("error",fail);setTimeout(finish,3500);return;}tag=document.createElement("script");tag.id=id;tag.setAttribute("data-namespace",ns);tag.src=s;tag.async=true;tag.onload=ok;tag.onerror=fail;(document.head||document.body||document.documentElement).appendChild(tag);setTimeout(finish,3500);}'."\n";
449 if($ppco_intent === 'subscription')
450 {
451 //260928.1739 WordPress rendered this inline JS with &#038;&#038; inside throw(res&&res.error), breaking the entire PayPal Button script. Use a ternary and || instead.
452 $code .= 'function getPlanId(){return fetch(u,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},body:enc({s2member_paypal_checkout_op:"get_plan_id",s2member_paypal_checkout_t:t})}).then(function(r){return r.json();}).then(function(res){if(res&&res.plan_id)return res.plan_id;throw(res ? (res.error || "plan_get_failed") : "plan_get_failed");});}'."\n";
453 $code .= 'var planId=null;'."\n";
454 $code .= 'function createSubscription(data,actions){if(planId)return actions.subscription.create({plan_id:planId,custom_id:cid,application_context:{shipping_preference:"NO_SHIPPING"}});return getPlanId().then(function(pid){planId=pid;return actions.subscription.create({plan_id:planId,custom_id:cid,application_context:{shipping_preference:"NO_SHIPPING"}});});}'."\n";
455 //260928.1739 WordPress rendered this inline JS with &#038;&#038; inside throw(res&&res.error), breaking the entire PayPal Button script. Use a ternary and || instead.
456 $code .= 'function onApprove(data){return fetch(u,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},body:enc({s2member_paypal_checkout_op:"confirm_subscription",s2member_paypal_checkout_t:t,subscription_id:(data&&data.subscriptionID?data.subscriptionID:"")})}).then(function(r){return r.json();}).then(function(res){if(res&&res.rtn_url&&res.rtn_post){postTo(res.rtn_url,res.rtn_post);return;}throw(res ? (res.error || "subscription_confirm_failed") : "subscription_confirm_failed");}).catch(function(e){showErr("Subscription could not be completed. Please try again.");});}'."\n";
457 $code .= 'function onCancel(){showInfo("Subscription cancelled.");}'."\n";
458 $code .= 'function onError(err){var m="PayPal error. Please try again.";try{if(err){if(typeof err==="string")m="PayPal error: "+err;else if(err.message)m="PayPal error: "+err.message;}}catch(x){}showErr(m);}'."\n";
459 $code .= 'function init(){loadSdk(function(P){var el=document.getElementById(d);if(!el){return;}if(el.getAttribute("data-s2m-ppco-rendered")==="1"){return;}if(!P||!P.Buttons){showErr("PayPal SDK failed to load.");return;}el.setAttribute("data-s2m-ppco-rendered","1");try{P.Buttons({fundingSource:P.FUNDING.PAYPAL,style:{layout:"vertical",tagline:false,height:40},createSubscription:createSubscription,onApprove:onApprove,onCancel:onCancel,onError:onError}).render("#"+d);}catch(x){el.removeAttribute("data-s2m-ppco-rendered");showErr("PayPal render failed.");}});}'."\n";
460 }
461 else
462 {
463 $code .= 'function request(op,vars){var body={s2member_paypal_checkout_op:op,s2member_paypal_checkout_t:t};for(var k in (vars||{})){if(vars.hasOwnProperty(k))body[k]=vars[k];}return fetch(u,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},body:enc(body)}).then(function(r){return r.json();});}'."\n";
464 $code .= 'function createOrder(){return request("create_order").then(function(res){if(res&&res.order_id)return res.order_id;throw(res ? (res.error || "order_create_failed") : "order_create_failed");});}'."\n";
465 //260928.1703 A completed PayPal capture can reach the verified webhook even when the browser loses its response. Poll only our durable state and submit its saved signed handoff; never issue a second capture on uncertainty.
466 $code .= 'function recoverOrder(n){return request("get_order_status").then(function(res){if(res&&res.fulfilled&&res.rtn_url&&res.rtn_post){postTo(res.rtn_url,res.rtn_post);return;}if(n>=20)throw "order_confirmation_pending";return new Promise(function(resolve){setTimeout(resolve,1200);}).then(function(){return recoverOrder(n+1);});});}'."\n";
467 $code .= 'function onApprove(data){var oid=data&&data.orderID?data.orderID:"";return request("capture_order",{order_id:oid}).catch(function(){return {recoverable:true};}).then(function(res){if(res&&res.rtn_url&&res.rtn_post){postTo(res.rtn_url,res.rtn_post);return;}if(res&&res.recoverable)return recoverOrder(0).catch(function(){showInfo("Payment confirmation is pending. Please do not pay again; check your email or contact support.");});showErr("Payment could not be confirmed. Please contact support before trying again.");});}'."\n";
468 $code .= 'function onCancel(){showInfo("Payment cancelled.");}'."\n";
469 $code .= 'function onError(err){var m="PayPal error. Please try again.";try{if(err){if(typeof err==="string")m="PayPal error: "+err;else if(err.message)m="PayPal error: "+err.message;}}catch(x){}showErr(m);}'."\n";
470 $code .= 'function init(){loadSdk(function(P){var el=document.getElementById(d);if(!el){return;}if(el.getAttribute("data-s2m-ppco-rendered")==="1"){return;}if(!P||!P.Buttons){showErr("PayPal SDK failed to load.");return;}el.setAttribute("data-s2m-ppco-rendered","1");try{P.Buttons({fundingSource:P.FUNDING.PAYPAL,style:{layout:"vertical",tagline:false,height:40},createOrder:createOrder,onApprove:onApprove,onCancel:onCancel,onError:onError}).render("#"+d);}catch(x){el.removeAttribute("data-s2m-ppco-rendered");showErr("PayPal render failed.");}});}'."\n";
471 }
472 $code .= 'if(document.readyState==="complete"){init();}else{window.addEventListener("load",init);}'."\n";
473 $code .= '})();'."\n";
474 $code .= '</script>'."\n";
475 $_code = $code;
476
477 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
478 do_action("ws_plugin__s2member_during_sc_paypal_sp_button", get_defined_vars ());
479 unset($__refs, $__v);
480
481 $code = c_ws_plugin__s2member_sc_paypal_button_e::sc_paypal_button_encryption ($code, get_defined_vars ());
482 return apply_filters("ws_plugin__s2member_sc_paypal_button", $code, get_defined_vars ());
483 }
484
485 $code = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/paypal-sp-checkout-button.php")));
486 $code = preg_replace ("/%%images%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . "/src/images")), $code);
487 $code = preg_replace ("/%%wpurl%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr (home_url ())), $code);
488
489 $code = preg_replace ("/%%endpoint%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")), $code);
490 $code = preg_replace ("/%%paypal_business%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"])), $code);
491 $code = preg_replace ("/%%paypal_merchant_id%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_merchant_id"])), $code);
492 $code = preg_replace ("/%%cancel_return%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr (home_url ("/"))), $code);
493 $code = preg_replace ("/%%notify_url%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr (home_url ("/?s2member_paypal_notify=1", $force_notify_url_scheme))), $code);
494 $code = preg_replace ("/%%return%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($success_return_url)), $code);
495 $code = preg_replace ("/%%custom%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["custom"])), $code);
496
497 $code = preg_replace ('/ name\="lc" value\="(.*?)"/', ' name="lc" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["lc"])) . '"', $code);
498 $code = preg_replace ('/ name\="no_shipping" value\="(.*?)"/', ' name="no_shipping" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["ns"])) . '"', $code);
499 $code = preg_replace ('/ name\="item_name" value\="(.*?)"/', ' name="item_name" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["desc"])) . '"', $code);
500 $code = preg_replace ('/ name\="item_number" value\="(.*?)"/', ' name="item_number" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["sp_ids_exp"])) . '"', $code);
501 $code = preg_replace ('/ name\="page_style" value\="(.*?)"/', ' name="page_style" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["ps"])) . '"', $code);
502 $code = preg_replace ('/ name\="currency_code" value\="(.*?)"/', ' name="currency_code" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["cc"])) . '"', $code);
503 $code = preg_replace ('/ name\="custom" value\="(.*?)"/', ' name="custom" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["custom"])) . '"', $code);
504
505 $code = preg_replace ('/ name\="invoice" value\="(.*?)"/', ' name="invoice" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_invoice_input_value)) . '"', $code);
506
507 $code = preg_replace ('/ name\="on0" value\="(.*?)"/', ' name="on0" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_on0_input_value)) . '"', $code);
508 $code = preg_replace ('/ name\="os0" value\="(.*?)"/', ' name="os0" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_os0_input_value)) . '"', $code);
509 $code = preg_replace ('/ name\="on1" value\="(.*?)"/', ' name="on1" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_on1_input_value)) . '"', $code);
510 $code = preg_replace ('/ name\="os1" value\="(.*?)"/', ' name="os1" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_os1_input_value)) . '"', $code);
511
512 $code = preg_replace ('/ name\="amount" value\="(.*?)"/', ' name="amount" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["ra"])) . '"', $code);
513
514 $code = $_code = ($attr["image"] && $attr["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["image"])) . '"', $code) : preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($default_image)) . '"', $code);
515
516 $code = ($attr["output"] === "anchor") ? '<a href="' . esc_attr (c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code)) . '"><img src="' . esc_attr (($attr["image"] && $attr["image"] !== "default") ? $attr["image"] : $default_image) . '" style="width:auto; height:auto; border:0;" alt="PayPal" /></a>' : $code;
517 $code = ($attr["output"] === "url") ? c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code) : $code;
518
519 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
520 do_action("ws_plugin__s2member_during_sc_paypal_sp_button", get_defined_vars ());
521 unset($__refs, $__v);
522 }
523 else if /* Independent Custom Capabilities. */ ($attr["level"] === "*")
524 {
525 $default_image = "https://www.paypal.com/" . (($attr["lang"]) ? $attr["lang"] : _x ("en_US", "s2member-front paypal-button-lang-code", "s2member")) . "/i/btn/btn_xpressCheckout.gif";
526
527 $paypal_on0_input_value = ($referencing = c_ws_plugin__s2member_utils_users::get_user_subscr_or_wp_id ()) ? "Referencing Customer ID" : "Originating Domain";
528 $paypal_os0_input_value = /* Current User's Paid Subscr. ID, or WP User ID, or domain. */ ($referencing) ? $referencing : $_SERVER["HTTP_HOST"];
529
530 $paypal_on1_input_value = /* Identifies the Customer's IP Address for tracking purposes. */ "Customer IP Address";
531 $paypal_os1_input_value = /* Current User's IP Address for tracking purposes. */ c_ws_plugin__s2member_utils_ip::current();
532
533 $paypal_invoice_input_value = /* s2Member's Unique Code~IP combo. */ uniqid () . "~" . c_ws_plugin__s2member_utils_ip::current();
534
535 //260928.1515 Give each rendered PayPal Checkout button a signed provisional identity; persist its Gateway Checkout only when the buyer starts, never on page render.
536 $ppco_gateway_checkout_identity = FALSE;
537 if(c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_enabled())
538 {
539 $ppco_gateway_checkout_identity = c_ws_plugin__s2member_gateway_checkouts::browser_identity();
540 $paypal_invoice_input_value = 's2mb-'.(string)$ppco_gateway_checkout_identity['id'];
541 }
542
543 $attr["level_ccaps_eotper"] = ($attr["rr"] === "BN" && $attr["rt"] !== "L") ? $attr["level"] . ":" . $attr["ccaps"] . ":" . $attr["rp"] . " " . $attr["rt"] : $attr["level"] . ":" . $attr["ccaps"];
544 $attr["level_ccaps_eotper"] = /* Clean any trailing separators from this string. */ rtrim ($attr["level_ccaps_eotper"], ":");
545
546 $success_return_url = /* s2Member handles this all by itself. However, it can be Filtered. */ home_url ("/?s2member_paypal_return=1", $force_return_url_scheme);
547 $success_return_url = apply_filters("ws_plugin__s2member_during_sc_paypal_button_success_return_url", $success_return_url, get_defined_vars ());
548
549
550 //260114 PayPal Checkout (REST) CCAPS (Independent Custom Capabilities) override.
551 // Uses server-side create + server-side capture, then posts into existing IPN + Return handlers.
552 if(c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_enabled())
553 {
554 $ppco_sandbox = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_sandbox();
555 $ppco_client_id = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"][($ppco_sandbox) ? "paypal_checkout_sandbox_client_id" : "paypal_checkout_client_id"];
556
557 $ppco_cc = strtoupper((string)$attr["cc"]);
558 $ppco_intent = 'capture';
559
560 $ppco_sdk_key = (($ppco_sandbox) ? 'sandbox' : 'live').'|'.$ppco_cc.'|'.$ppco_intent;
561
562 $ppco_sdk_just_loaded = false;
563 if(empty($ppco_sdks[$ppco_sdk_key]) || !is_array($ppco_sdks[$ppco_sdk_key]))
564 {
565 $ppco_sdks[$ppco_sdk_key] = array(
566 'ns' => 's2m_ppco_'.substr(md5($ppco_sdk_key), 0, 10),
567 'id' => 's2member_ppco_sdk_'.substr(md5($ppco_sdk_key), 0, 10),
568 );
569 $ppco_sdk_just_loaded = true;
570 }
571
572 $ppco_sdk_ns = (string)$ppco_sdks[$ppco_sdk_key]['ns'];
573 $ppco_sdk_id = (string)$ppco_sdks[$ppco_sdk_key]['id'];
574
575 $ppco_endpoint = home_url("/?s2member_paypal_checkout=1", $force_notify_url_scheme);
576 $ppco_cancel = home_url("/");
577
578 $ppco_token = array(
579 'exp' => time() + 3600,
580
581 'invoice' => $paypal_invoice_input_value,
582 'ip' => c_ws_plugin__s2member_utils_ip::current(),
583 'item_name' => $attr["desc"],
584 'item_number' => $attr["level_ccaps_eotper"],
585 'custom' => $attr["custom"],
586
587 'amount' => $attr["ra"],
588 'cc' => $ppco_cc,
589 'ns' => $attr["ns"],
590
591 'rr' => 'BN',
592
593 'on0' => $paypal_on0_input_value,
594 'os0' => $paypal_os0_input_value,
595 'on1' => $paypal_on1_input_value,
596 'os1' => $paypal_os1_input_value,
597
598 'return' => $success_return_url,
599 'cancel' => $ppco_cancel,
600
601 'checksum' => md5($paypal_invoice_input_value.c_ws_plugin__s2member_utils_ip::current().$attr["level_ccaps_eotper"]),
602 );
603
604 //260928.1515 Bind the PayPal invoice and encrypted purchase terms to the same provisional Gateway Checkout identity, including in anchor/url mode.
605 if($ppco_gateway_checkout_identity)
606 {
607 $ppco_token['gateway_checkout_id'] = (string)$ppco_gateway_checkout_identity['id'];
608 $ppco_token['gateway_checkout_token'] = (string)$ppco_gateway_checkout_identity['token'];
609 }
610
611 $ppco_token = urlencode(c_ws_plugin__s2member_utils_encryption::encrypt(serialize($ppco_token)));
612
613 // output="anchor|url" support (no JS SDK; redirects through s2Member, then to PayPal approval URL).
614 if($attr["output"] === "anchor" || $attr["output"] === "url")
615 {
616 $ppco_redirect_url = $ppco_endpoint.'&s2member_paypal_checkout_op=redirect&s2member_paypal_checkout_t='.$ppco_token;
617
618 if($attr["output"] === "url")
619 $code = $_code = $ppco_redirect_url;
620
621 else // output="anchor"
622 {
623 $img_src = ($attr["image"] && $attr["image"] !== "default") ? $attr["image"] : $default_image;
624 $code = $_code = '<a class="ws-plugin--s2member-paypal-button ws-plugin--s2member-paypal-anchor" href="'.esc_attr($ppco_redirect_url).'"><img class="ws-plugin--s2member-paypal-button-img" src="'.esc_attr($img_src).'" style="width:auto; height:auto; border:0; margin:0;" alt="PayPal" /></a>';
625 }
626
627 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
628 do_action("ws_plugin__s2member_during_sc_paypal_ccaps_button", get_defined_vars ());
629 unset($__refs, $__v);
630
631 $code = c_ws_plugin__s2member_sc_paypal_button_e::sc_paypal_button_encryption ($code, get_defined_vars ());
632 return apply_filters("ws_plugin__s2member_sc_paypal_button", $code, get_defined_vars ());
633 }
634
635 $ppco_div_id = 's2member_ppco_btn_'.md5($paypal_invoice_input_value.$attr["level_ccaps_eotper"]);
636 $ppco_err_id = 's2member_ppco_err_'.md5($paypal_invoice_input_value.$attr["level_ccaps_eotper"]);
637
638 $ppco_locale = ($attr["lang"]) ? (string)$attr["lang"] : '';
639 $ppco_lc = ($attr["lc"]) ? (string)$attr["lc"] : '';
640
641 if(!$ppco_locale && $ppco_lc)
642 {
643 $site_locale = (string)get_locale();
644 if(preg_match('/^([a-z]{2})[_-]/i', $site_locale, $m))
645 $ppco_locale = strtolower($m[1]).'_'.strtoupper($ppco_lc);
646 else
647 $ppco_locale = 'en_'.strtoupper($ppco_lc);
648 }
649
650 $ppco_locale_q = ($ppco_locale) ? '&locale='.rawurlencode($ppco_locale) : '';
651 $ppco_buyer_country_q = ($ppco_sandbox && $ppco_lc) ? '&buyer-country='.rawurlencode(strtoupper($ppco_lc)) : '';
652
653 $ppco_sdk_src = ($ppco_sandbox ? 'https://www.sandbox.paypal.com/sdk/js' : 'https://www.paypal.com/sdk/js');
654 //260114 !!! Independent CCAPS is capture-only; conditional subscription path below is dead code (cleanup/refactor later).
655 if($ppco_intent === 'subscription')
656 $ppco_sdk_src = $ppco_sdk_src.'?client-id='.rawurlencode($ppco_client_id).'&currency='.rawurlencode($ppco_cc).'&vault=true&intent=subscription&disable-funding=card'.$ppco_buyer_country_q.$ppco_locale_q;
657 else
658 $ppco_sdk_src = $ppco_sdk_src.'?client-id='.rawurlencode($ppco_client_id).'&currency='.rawurlencode($ppco_cc).'&intent=capture&commit=true&disable-funding=card'.$ppco_buyer_country_q.$ppco_locale_q;
659
660 $code = '<div id="'.esc_attr($ppco_div_id).'" class="ws-plugin--s2member-paypal-button ws-plugin--s2member-ppco-button" style="max-width:145px; width:auto; margin:0;"></div>'."\n";
661 $code .= '<div id="'.esc_attr($ppco_err_id).'" class="ws-plugin--s2member-ppco-message" style="display:none; margin:0;"></div>'."\n";
662
663 $ppco_sdk_src = apply_filters('ws_plugin__s2member_ppco_sdk_src', $ppco_sdk_src, get_defined_vars());
664
665 if($ppco_sdk_just_loaded)
666 {
667 $code .= '<script id="'.esc_attr($ppco_sdk_id).'" data-namespace="'.esc_attr($ppco_sdk_ns).'" src="'.esc_attr($ppco_sdk_src).'"></script>'."\n";
668 }
669
670 $code .= '<script type="text/javascript">'."\n";
671 $code .= '(function(){'."\n";
672 $code .= 'var d="'.esc_js($ppco_div_id).'";'."\n";
673 $code .= 'var e="'.esc_js($ppco_err_id).'";'."\n";
674 $code .= 'var t="'.esc_js($ppco_token).'";'."\n";
675 $code .= 'var u="'.esc_js($ppco_endpoint).'";'."\n";
676 //260928.1739 Bind to the SDK script actually emitted above and encode its URL as JavaScript, not HTML entities.
677 $code .= 'var ns="'.esc_js($ppco_sdk_ns).'";'."\n";
678 $code .= 'var sdkId="'.esc_js($ppco_sdk_id).'";'."\n";
679 $code .= 'var s='.wp_json_encode($ppco_sdk_src, JSON_HEX_AMP | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT).';'."\n";
680 $code .= 'var cid="'.esc_js($paypal_invoice_input_value).'";'."\n";
681 //260819.0042 Keep standalone Checkout feedback consistent with Pro-Forms while distinguishing cancellation from errors.
682 $code .= 'function showMsg(m,t){try{var el=document.getElementById(e);if(el){el.style.display="block";el.innerHTML="<span class=\"ws-plugin--s2member-ppco-"+(t==="info"?"info":"error")+"\">"+m+"</span>";}}catch(x){}}function showErr(m){showMsg(m,"error");}function showInfo(m){showMsg(m,"info");}'."\n";
683 $code .= 'function postTo(url, data){var f=document.createElement("form");f.method="post";f.acceptCharset="UTF-8";f.action=url;for(var k in data){if(!data.hasOwnProperty(k))continue;var i=document.createElement("input");i.type="hidden";i.name=k;i.value=data[k];f.appendChild(i);}document.body.appendChild(f);f.submit();}'."\n"; //260817 Keep signed PayPal Checkout returns in UTF-8.
684 $code .= 'function enc(o){var a=[];for(var k in o){if(!o.hasOwnProperty(k))continue;a.push(encodeURIComponent(k)+"="+encodeURIComponent(o[k]));}return a.join("&");}'."\n";
685 $code .= 'function loadSdk(cb){var P=window[ns];if(P&&P.Buttons){cb(P);return;}var id=sdkId,tag=document.getElementById(id),done=false;function finish(){if(done)return;done=true;cb(window[ns]&&window[ns].Buttons?window[ns]:null);}function ok(){finish();}function fail(){finish();}if(tag){if(window[ns]&&window[ns].Buttons){finish();return;}if(tag.getAttribute("src")!==s){tag.setAttribute("src",s);}if(tag.readyState==="complete"||tag.readyState==="loaded"){setTimeout(finish,0);return;}tag.addEventListener("load",ok);tag.addEventListener("error",fail);setTimeout(finish,3500);return;}tag=document.createElement("script");tag.id=id;tag.setAttribute("data-namespace",ns);tag.src=s;tag.async=true;tag.onload=ok;tag.onerror=fail;(document.head||document.body||document.documentElement).appendChild(tag);setTimeout(finish,3500);}'."\n";
686 if($ppco_intent === 'subscription')
687 {
688 $code .= 'function getPlanId(){return fetch(u,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},body:enc({s2member_paypal_checkout_op:"get_plan_id",s2member_paypal_checkout_t:t})}).then(function(r){return r.json();}).then(function(res){if(res&&res.plan_id)return res.plan_id;throw(res ? (res.error || "plan_get_failed") : "plan_get_failed");});}'."\n";
689 $code .= 'var planId=null;'."\n";
690 $code .= 'function createSubscription(data,actions){if(planId)return actions.subscription.create({plan_id:planId,custom_id:cid,application_context:{shipping_preference:"NO_SHIPPING"}});return getPlanId().then(function(pid){planId=pid;return actions.subscription.create({plan_id:planId,custom_id:cid,application_context:{shipping_preference:"NO_SHIPPING"}});});}'."\n";
691 //260928.1739 WordPress rendered this inline JS with &#038;&#038; inside throw(res&&res.error), breaking the entire PayPal Button script. Use a ternary and || instead.
692 $code .= 'function onApprove(data){return fetch(u,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},body:enc({s2member_paypal_checkout_op:"confirm_subscription",s2member_paypal_checkout_t:t,subscription_id:(data&&data.subscriptionID?data.subscriptionID:"")})}).then(function(r){return r.json();}).then(function(res){if(res&&res.rtn_url&&res.rtn_post){postTo(res.rtn_url,res.rtn_post);return;}throw(res ? (res.error || "subscription_confirm_failed") : "subscription_confirm_failed");}).catch(function(e){showErr("Subscription could not be completed. Please try again.");});}'."\n";
693 $code .= 'function onCancel(){showInfo("Subscription cancelled.");}'."\n";
694 $code .= 'function onError(err){var m="PayPal error. Please try again.";try{if(err){if(typeof err==="string")m="PayPal error: "+err;else if(err.message)m="PayPal error: "+err.message;}}catch(x){}showErr(m);}'."\n";
695 $code .= 'function init(){loadSdk(function(P){var el=document.getElementById(d);if(!el){return;}if(el.getAttribute("data-s2m-ppco-rendered")==="1"){return;}if(!P||!P.Buttons){showErr("PayPal SDK failed to load.");return;}el.setAttribute("data-s2m-ppco-rendered","1");try{P.Buttons({fundingSource:P.FUNDING.PAYPAL,style:{layout:"vertical",tagline:false,height:40},createSubscription:createSubscription,onApprove:onApprove,onCancel:onCancel,onError:onError}).render("#"+d);}catch(x){el.removeAttribute("data-s2m-ppco-rendered");showErr("PayPal render failed.");}});}'."\n";
696 }
697 else
698 {
699 $code .= 'function request(op,vars){var body={s2member_paypal_checkout_op:op,s2member_paypal_checkout_t:t};for(var k in (vars||{})){if(vars.hasOwnProperty(k))body[k]=vars[k];}return fetch(u,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},body:enc(body)}).then(function(r){return r.json();});}'."\n";
700 $code .= 'function createOrder(){return request("create_order").then(function(res){if(res&&res.order_id)return res.order_id;throw(res ? (res.error || "order_create_failed") : "order_create_failed");});}'."\n";
701 //260928.1703 A completed PayPal capture can reach the verified webhook even when the browser loses its response. Poll only our durable state and submit its saved signed handoff; never issue a second capture on uncertainty.
702 $code .= 'function recoverOrder(n){return request("get_order_status").then(function(res){if(res&&res.fulfilled&&res.rtn_url&&res.rtn_post){postTo(res.rtn_url,res.rtn_post);return;}if(n>=20)throw "order_confirmation_pending";return new Promise(function(resolve){setTimeout(resolve,1200);}).then(function(){return recoverOrder(n+1);});});}'."\n";
703 $code .= 'function onApprove(data){var oid=data&&data.orderID?data.orderID:"";return request("capture_order",{order_id:oid}).catch(function(){return {recoverable:true};}).then(function(res){if(res&&res.rtn_url&&res.rtn_post){postTo(res.rtn_url,res.rtn_post);return;}if(res&&res.recoverable)return recoverOrder(0).catch(function(){showInfo("Payment confirmation is pending. Please do not pay again; check your email or contact support.");});showErr("Payment could not be confirmed. Please contact support before trying again.");});}'."\n";
704 $code .= 'function onCancel(){showInfo("Payment cancelled.");}'."\n";
705 $code .= 'function onError(err){var m="PayPal error. Please try again.";try{if(err){if(typeof err==="string")m="PayPal error: "+err;else if(err.message)m="PayPal error: "+err.message;}}catch(x){}showErr(m);}'."\n";
706 $code .= 'function init(){loadSdk(function(P){var el=document.getElementById(d);if(!el){return;}if(el.getAttribute("data-s2m-ppco-rendered")==="1"){return;}if(!P||!P.Buttons){showErr("PayPal SDK failed to load.");return;}el.setAttribute("data-s2m-ppco-rendered","1");try{P.Buttons({fundingSource:P.FUNDING.PAYPAL,style:{layout:"vertical",tagline:false,height:40},createOrder:createOrder,onApprove:onApprove,onCancel:onCancel,onError:onError}).render("#"+d);}catch(x){el.removeAttribute("data-s2m-ppco-rendered");showErr("PayPal render failed.");}});}'."\n";
707 }
708 $code .= 'if(document.readyState==="complete"){init();}else{window.addEventListener("load",init);}'."\n";
709 $code .= '})();'."\n";
710 $code .= '</script>'."\n";
711 $_code = $code;
712
713 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
714 do_action("ws_plugin__s2member_during_sc_paypal_ccaps_button", get_defined_vars ());
715 unset($__refs, $__v);
716
717 $code = c_ws_plugin__s2member_sc_paypal_button_e::sc_paypal_button_encryption ($code, get_defined_vars ());
718 return apply_filters("ws_plugin__s2member_sc_paypal_button", $code, get_defined_vars ());
719 }
720
721 $code = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/paypal-ccaps-checkout-button.php")));
722 $code = preg_replace ("/%%images%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . "/src/images")), $code);
723 $code = preg_replace ("/%%wpurl%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr (home_url ())), $code);
724
725 $code = preg_replace ("/%%endpoint%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")), $code);
726 $code = preg_replace ("/%%paypal_business%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"])), $code);
727 $code = preg_replace ("/%%paypal_merchant_id%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_merchant_id"])), $code);
728 $code = preg_replace ("/%%cancel_return%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr (home_url ("/"))), $code);
729 $code = preg_replace ("/%%notify_url%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr (home_url ("/?s2member_paypal_notify=1", $force_notify_url_scheme))), $code);
730 $code = preg_replace ("/%%return%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($success_return_url)), $code);
731 $code = preg_replace ("/%%custom%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["custom"])), $code);
732
733 $code = preg_replace ('/ name\="lc" value\="(.*?)"/', ' name="lc" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["lc"])) . '"', $code);
734 $code = preg_replace ('/ name\="no_shipping" value\="(.*?)"/', ' name="no_shipping" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["ns"])) . '"', $code);
735 $code = preg_replace ('/ name\="item_name" value\="(.*?)"/', ' name="item_name" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["desc"])) . '"', $code);
736 $code = preg_replace ('/ name\="item_number" value\="(.*?)"/', ' name="item_number" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["level_ccaps_eotper"])) . '"', $code);
737 $code = preg_replace ('/ name\="page_style" value\="(.*?)"/', ' name="page_style" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["ps"])) . '"', $code);
738 $code = preg_replace ('/ name\="currency_code" value\="(.*?)"/', ' name="currency_code" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["cc"])) . '"', $code);
739 $code = preg_replace ('/ name\="custom" value\="(.*?)"/', ' name="custom" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["custom"])) . '"', $code);
740
741 $code = preg_replace ('/ name\="invoice" value\="(.*?)"/', ' name="invoice" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_invoice_input_value)) . '"', $code);
742
743 $code = preg_replace ('/ name\="on0" value\="(.*?)"/', ' name="on0" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_on0_input_value)) . '"', $code);
744 $code = preg_replace ('/ name\="os0" value\="(.*?)"/', ' name="os0" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_os0_input_value)) . '"', $code);
745 $code = preg_replace ('/ name\="on1" value\="(.*?)"/', ' name="on1" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_on1_input_value)) . '"', $code);
746 $code = preg_replace ('/ name\="os1" value\="(.*?)"/', ' name="os1" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_os1_input_value)) . '"', $code);
747
748 $code = preg_replace ('/ name\="amount" value\="(.*?)"/', ' name="amount" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["ra"])) . '"', $code);
749
750 $code = $_code = ($attr["image"] && $attr["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["image"])) . '"', $code) : preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($default_image)) . '"', $code);
751
752 $code = ($attr["output"] === "anchor") ? '<a href="' . esc_attr (c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code)) . '"><img src="' . esc_attr (($attr["image"] && $attr["image"] !== "default") ? $attr["image"] : $default_image) . '" style="width:auto; height:auto; border:0;" alt="PayPal" /></a>' : $code;
753 $code = ($attr["output"] === "url") ? c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code) : $code;
754
755 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
756 do_action("ws_plugin__s2member_during_sc_paypal_ccaps_button", get_defined_vars ());
757 unset($__refs, $__v);
758 }
759 else // Otherwise, we'll process this Button normally, using Membership routines.
760 {
761 $default_image = "https://www.paypal.com/" . (($attr["lang"]) ? $attr["lang"] : _x ("en_US", "s2member-front paypal-button-lang-code", "s2member")) . "/i/btn/btn_xpressCheckout.gif";
762
763 $paypal_on0_input_value = ($referencing = c_ws_plugin__s2member_utils_users::get_user_subscr_or_wp_id ()) ? "Referencing Customer ID" : "Originating Domain";
764 $paypal_os0_input_value = /* Current User's Paid Subscr. ID, or WP User ID, or domain. */ ($referencing) ? $referencing : $_SERVER["HTTP_HOST"];
765
766 $paypal_on1_input_value = /* Identifies the Customer's IP Address for tracking purposes. */ "Customer IP Address";
767 $paypal_os1_input_value = /* Current User's IP Address for tracking purposes. */ c_ws_plugin__s2member_utils_ip::current();
768
769 $paypal_invoice_input_value = /* s2Member's Unique Code~IP combo. */ uniqid () . "~" . c_ws_plugin__s2member_utils_ip::current();
770
771 //260928.1515 Give each rendered PayPal Checkout button a signed provisional identity; persist its Gateway Checkout only when the buyer starts, never on page render.
772 $ppco_gateway_checkout_identity = FALSE;
773 if(c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_enabled())
774 {
775 $ppco_gateway_checkout_identity = c_ws_plugin__s2member_gateway_checkouts::browser_identity();
776 $paypal_invoice_input_value = 's2mb-'.(string)$ppco_gateway_checkout_identity['id'];
777 }
778
779 $attr["desc"] = (!$attr["desc"]) ? $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $attr["level"] . "_label"] : $attr["desc"];
780
781 // PayPal Checkout: rr=0 with no trial/initial should behave like Buy Now (one-time),
782 // so s2Member’s standard Buy Now/EOT routines run (mirrors other gateways).
783 if(c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_enabled()
784 && (string)$attr["rr"] === '0'
785 && (float)$attr["ta"] <= 0
786 && (int)$attr["tp"] <= 0)
787 {
788 $attr["rr"] = 'BN';
789 }
790
791 $attr["level_ccaps_eotper"] = ($attr["rr"] === "BN" && $attr["rt"] !== "L") ? $attr["level"] . ":" . $attr["ccaps"] . ":" . $attr["rp"] . " " . $attr["rt"] : $attr["level"] . ":" . $attr["ccaps"];
792 $attr["level_ccaps_eotper"] = /* Clean any trailing separators from this string. */ rtrim ($attr["level_ccaps_eotper"], ":");
793
794 $success_return_tra = array("ta" => $attr["ta"], "tp" => $attr["tp"], "tt" => $attr["tt"], "ra" => $attr["ra"], "rp" => $attr["rp"], "rt" => $attr["rt"], "rr" => $attr["rr"], "rrt" => $attr["rrt"], "rra" => $attr["rra"], "invoice" => $paypal_invoice_input_value, "checksum" => md5 ($paypal_invoice_input_value . c_ws_plugin__s2member_utils_ip::current() . $attr["level_ccaps_eotper"]));
795
796 $success_return_url = /* s2Member handles this all by itself. However, it can be Filtered (see below). */ home_url ("/?s2member_paypal_return=1", $force_return_url_scheme);
797 $success_return_url = add_query_arg ("s2member_paypal_return_tra", urlencode (c_ws_plugin__s2member_utils_encryption::encrypt (serialize ($success_return_tra))), $success_return_url);
798 $success_return_url = apply_filters("ws_plugin__s2member_during_sc_paypal_button_success_return_url", $success_return_url, get_defined_vars ());
799
800 //260106 PayPal Checkout (REST) Buy Now (rr=BN) override.
801 // Uses server-side create + server-side capture/confirm, then posts into existing IPN + Return handlers.
802 if(c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_enabled())
803 {
804 $ppco_sandbox = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_is_sandbox();
805 $ppco_client_id = (string)$GLOBALS["WS_PLUGIN__"]["s2member"]["o"][($ppco_sandbox) ? "paypal_checkout_sandbox_client_id" : "paypal_checkout_client_id"];
806
807 $ppco_cc = strtoupper((string)$attr["cc"]);
808 $ppco_intent = ($attr["rr"] === "BN") ? 'capture' : 'subscription';
809
810 $ppco_sdk_key = (($ppco_sandbox) ? 'sandbox' : 'live').'|'.$ppco_cc.'|'.$ppco_intent;
811
812 $ppco_sdk_just_loaded = false;
813 if(empty($ppco_sdks[$ppco_sdk_key]) || !is_array($ppco_sdks[$ppco_sdk_key]))
814 {
815 $ppco_sdks[$ppco_sdk_key] = array(
816 'ns' => 's2m_ppco_'.substr(md5($ppco_sdk_key), 0, 10),
817 'id' => 's2member_ppco_sdk_'.substr(md5($ppco_sdk_key), 0, 10),
818 );
819 $ppco_sdk_just_loaded = true;
820 }
821
822 $ppco_sdk_ns = (string)$ppco_sdks[$ppco_sdk_key]['ns'];
823 $ppco_sdk_id = (string)$ppco_sdks[$ppco_sdk_key]['id'];
824
825 $ppco_endpoint = home_url("/?s2member_paypal_checkout=1", $force_notify_url_scheme);
826 $ppco_cancel = home_url("/");
827
828 $ppco_token = array(
829 'exp' => time() + 3600,
830
831 'invoice' => $paypal_invoice_input_value,
832 'ip' => c_ws_plugin__s2member_utils_ip::current(),
833 'item_name' => $attr["desc"],
834 'item_number' => $attr["level_ccaps_eotper"],
835 'custom' => $attr["custom"],
836
837 'amount' => $attr["ra"],
838 'cc' => $ppco_cc,
839 'ns' => $attr["ns"],
840
841 'rr' => $attr["rr"],
842 'rp' => $attr["rp"],
843 'rt' => $attr["rt"],
844
845 'rrt' => $attr["rrt"],
846 'rra' => $attr["rra"],
847
848 'ta' => $attr["ta"],
849 'tp' => $attr["tp"],
850 'tt' => $attr["tt"],
851
852 'on0' => $paypal_on0_input_value,
853 'os0' => $paypal_os0_input_value,
854 'on1' => $paypal_on1_input_value,
855 'os1' => $paypal_os1_input_value,
856
857 'old__subscr_gateway' => get_user_option('s2member_subscr_gateway'),
858 'old__subscr_id' => get_user_option('s2member_subscr_id'),
859 'old__subscr_baid' => get_user_option('s2member_subscr_baid'),
860 'old__subscr_cid' => get_user_option('s2member_subscr_cid'),
861 'old__ipn_signup_vars' => c_ws_plugin__s2member_utils_users::get_user_ipn_signup_vars(), //260408 Capture the old context before PayPal/webhook processing can update the member's current profile.
862
863 'return' => $success_return_url,
864 'cancel' => $ppco_cancel,
865
866 'checksum' => md5($paypal_invoice_input_value.c_ws_plugin__s2member_utils_ip::current().$attr["level_ccaps_eotper"]),
867 );
868
869 //260928.1515 Bind the PayPal invoice and encrypted purchase terms to the same provisional Gateway Checkout identity, including in anchor/url mode.
870 if($ppco_gateway_checkout_identity)
871 {
872 $ppco_token['gateway_checkout_id'] = (string)$ppco_gateway_checkout_identity['id'];
873 $ppco_token['gateway_checkout_token'] = (string)$ppco_gateway_checkout_identity['token'];
874 }
875
876 $ppco_token = urlencode(c_ws_plugin__s2member_utils_encryption::encrypt(serialize($ppco_token)));
877
878 // output="anchor|url" support (no JS SDK; redirects through s2Member, then to PayPal approval URL).
879 if($attr["output"] === "anchor" || $attr["output"] === "url")
880 {
881 $ppco_redirect_url = $ppco_endpoint.'&s2member_paypal_checkout_op=redirect&s2member_paypal_checkout_t='.$ppco_token;
882
883 if($attr["output"] === "url")
884 $code = $_code = $ppco_redirect_url;
885
886 else // output="anchor"
887 {
888 $img_src = ($attr["image"] && $attr["image"] !== "default") ? $attr["image"] : $default_image;
889 $code = $_code = '<a class="ws-plugin--s2member-paypal-button ws-plugin--s2member-paypal-anchor" href="'.esc_attr($ppco_redirect_url).'"><img class="ws-plugin--s2member-paypal-button-img" src="'.esc_attr($img_src).'" style="width:auto; height:auto; border:0; margin:0;" alt="PayPal" /></a>';
890 }
891
892 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
893 do_action("ws_plugin__s2member_during_sc_paypal_button", get_defined_vars ());
894 unset($__refs, $__v);
895
896 $code = c_ws_plugin__s2member_sc_paypal_button_e::sc_paypal_button_encryption ($code, get_defined_vars ());
897 return apply_filters("ws_plugin__s2member_sc_paypal_button", $code, get_defined_vars ());
898 }
899
900 $ppco_div_id = 's2member_ppco_btn_'.md5($paypal_invoice_input_value.$attr["level_ccaps_eotper"]);
901 $ppco_err_id = 's2member_ppco_err_'.md5($paypal_invoice_input_value.$attr["level_ccaps_eotper"]);
902
903 $ppco_locale = ($attr["lang"]) ? (string)$attr["lang"] : '';
904 $ppco_lc = ($attr["lc"]) ? (string)$attr["lc"] : '';
905
906 if(!$ppco_locale && $ppco_lc)
907 {
908 $site_locale = (string)get_locale();
909 if(preg_match('/^([a-z]{2})[_-]/i', $site_locale, $m))
910 $ppco_locale = strtolower($m[1]).'_'.strtoupper($ppco_lc);
911 else
912 $ppco_locale = 'en_'.strtoupper($ppco_lc);
913 }
914
915 $ppco_locale_q = ($ppco_locale) ? '&locale='.rawurlencode($ppco_locale) : '';
916 $ppco_buyer_country_q = ($ppco_sandbox && $ppco_lc) ? '&buyer-country='.rawurlencode(strtoupper($ppco_lc)) : '';
917
918 $ppco_sdk_src = ($ppco_sandbox ? 'https://www.sandbox.paypal.com/sdk/js' : 'https://www.paypal.com/sdk/js');
919 if($ppco_intent === 'subscription')
920 $ppco_sdk_src = $ppco_sdk_src.'?client-id='.rawurlencode($ppco_client_id).'&currency='.rawurlencode($ppco_cc).'&vault=true&intent=subscription&disable-funding=card'.$ppco_buyer_country_q.$ppco_locale_q;
921 else
922 $ppco_sdk_src = $ppco_sdk_src.'?client-id='.rawurlencode($ppco_client_id).'&currency='.rawurlencode($ppco_cc).'&intent=capture&commit=true&disable-funding=card'.$ppco_buyer_country_q.$ppco_locale_q;
923
924 $code = '<div id="'.esc_attr($ppco_div_id).'" class="ws-plugin--s2member-paypal-button ws-plugin--s2member-ppco-button" style="max-width:145px; width:auto; margin:0;"></div>'."\n";
925 $code .= '<div id="'.esc_attr($ppco_err_id).'" class="ws-plugin--s2member-ppco-message" style="display:none; margin:0;"></div>'."\n";
926
927 $ppco_sdk_src = apply_filters('ws_plugin__s2member_ppco_sdk_src', $ppco_sdk_src, get_defined_vars());
928
929 if($ppco_sdk_just_loaded)
930 {
931 $code .= '<script id="'.esc_attr($ppco_sdk_id).'" data-namespace="'.esc_attr($ppco_sdk_ns).'" src="'.esc_attr($ppco_sdk_src).'"></script>'."\n";
932 }
933
934 $code .= '<script type="text/javascript">'."\n";
935 $code .= '(function(){'."\n";
936 $code .= 'var d="'.esc_js($ppco_div_id).'";'."\n";
937 $code .= 'var e="'.esc_js($ppco_err_id).'";'."\n";
938 $code .= 'var t="'.esc_js($ppco_token).'";'."\n";
939 $code .= 'var u="'.esc_js($ppco_endpoint).'";'."\n";
940 //260928.1739 Bind to the SDK script actually emitted above and encode its URL as JavaScript, not HTML entities.
941 $code .= 'var ns="'.esc_js($ppco_sdk_ns).'";'."\n";
942 $code .= 'var sdkId="'.esc_js($ppco_sdk_id).'";'."\n";
943 $code .= 'var s='.wp_json_encode($ppco_sdk_src, JSON_HEX_AMP | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT).';'."\n";
944 $code .= 'var cid="'.esc_js($paypal_invoice_input_value).'";'."\n";
945 //260819.0042 Keep standalone Checkout feedback consistent with Pro-Forms while distinguishing cancellation from errors.
946 $code .= 'function showMsg(m,t){try{var el=document.getElementById(e);if(el){el.style.display="block";el.innerHTML="<span class=\"ws-plugin--s2member-ppco-"+(t==="info"?"info":"error")+"\">"+m+"</span>";}}catch(x){}}function showErr(m){showMsg(m,"error");}function showInfo(m){showMsg(m,"info");}'."\n";
947 $code .= 'function postTo(url, data){var f=document.createElement("form");f.method="post";f.acceptCharset="UTF-8";f.action=url;for(var k in data){if(!data.hasOwnProperty(k))continue;var i=document.createElement("input");i.type="hidden";i.name=k;i.value=data[k];f.appendChild(i);}document.body.appendChild(f);f.submit();}'."\n"; //260817 Keep signed PayPal Checkout returns in UTF-8.
948 $code .= 'function enc(o){var a=[];for(var k in o){if(!o.hasOwnProperty(k))continue;a.push(encodeURIComponent(k)+"="+encodeURIComponent(o[k]));}return a.join("&");}'."\n";
949 $code .= 'function loadSdk(cb){var P=window[ns];if(P&&P.Buttons){cb(P);return;}var id=sdkId,tag=document.getElementById(id),done=false;function finish(){if(done)return;done=true;cb(window[ns]&&window[ns].Buttons?window[ns]:null);}function ok(){finish();}function fail(){finish();}if(tag){if(window[ns]&&window[ns].Buttons){finish();return;}if(tag.getAttribute("src")!==s){tag.setAttribute("src",s);}if(tag.readyState==="complete"||tag.readyState==="loaded"){setTimeout(finish,0);return;}tag.addEventListener("load",ok);tag.addEventListener("error",fail);setTimeout(finish,3500);return;}tag=document.createElement("script");tag.id=id;tag.setAttribute("data-namespace",ns);tag.src=s;tag.async=true;tag.onload=ok;tag.onerror=fail;(document.head||document.body||document.documentElement).appendChild(tag);setTimeout(finish,3500);}'."\n";
950 if($ppco_intent === 'subscription')
951 {
952 //260928.1540 Move Framework subscription creation onto the same server-side provider/idempotency path Pro-Forms use. Only the persisted ID reaches the PayPal SDK for buyer approval.
953 $code .= 'function request(op,vars){var body={s2member_paypal_checkout_op:op,s2member_paypal_checkout_t:t};for(var k in (vars||{})){if(vars.hasOwnProperty(k))body[k]=vars[k];}return fetch(u,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},body:enc(body)}).then(function(r){return r.json();});}' . "\n";
954 $code .= 'function waitForSubscription(n){return request("get_subscription_id").then(function(res){if(res&&res.subscription_id)return res.subscription_id;if(n>=20)throw "subscription_create_unresolved";return new Promise(function(resolve){setTimeout(resolve,1000);}).then(function(){return waitForSubscription(n+1);});});}' . "\n";
955 $code .= 'function createSubscription(){return request("create_subscription").then(function(res){if(res&&res.subscription_id)return res.subscription_id;if(res&&res.recoverable)return waitForSubscription(0);throw(res ? (res.error || "subscription_create_failed") : "subscription_create_failed");});}' . "\n";
956 //260928.1540 PayPal can report APPROVED before subscription ACTIVATED; poll the same backend until entitlement is confirmed or the activation webhook fulfills off-session.
957 //260928.1739 WordPress rendered this inline JS with &#038;&#038; inside throw(res&&res.error), breaking the entire PayPal Button script. Use a ternary and || instead.
958 $code .= 'function onApprove(data){var sid=data&&data.subscriptionID?data.subscriptionID:"";function finish(n){return request("confirm_subscription",{subscription_id:sid}).then(function(res){if(res&&res.rtn_url&&res.rtn_post){postTo(res.rtn_url,res.rtn_post);return;}if(res&&res.pending_activation&&n<25){return new Promise(function(resolve){setTimeout(resolve,1200);}).then(function(){return finish(n+1);});}throw(res ? (res.error || "subscription_confirm_failed") : "subscription_confirm_failed");});}return finish(0).catch(function(){showErr("Subscription could not be completed. Please try again.");});}' . "\n";
959 $code .= 'function onCancel(){showInfo("Subscription cancelled.");}'."\n";
960 $code .= 'function onError(err){var m="PayPal error. Please try again.";try{if(err){if(typeof err==="string")m="PayPal error: "+err;else if(err.message)m="PayPal error: "+err.message;}}catch(x){}showErr(m);}'."\n";
961 $code .= 'function init(){loadSdk(function(P){var el=document.getElementById(d);if(!el){return;}if(el.getAttribute("data-s2m-ppco-rendered")==="1"){return;}if(!P||!P.Buttons){showErr("PayPal SDK failed to load.");return;}el.setAttribute("data-s2m-ppco-rendered","1");try{P.Buttons({fundingSource:P.FUNDING.PAYPAL,style:{layout:"vertical",tagline:false,height:40},createSubscription:createSubscription,onApprove:onApprove,onCancel:onCancel,onError:onError}).render("#"+d);}catch(x){el.removeAttribute("data-s2m-ppco-rendered");showErr("PayPal render failed.");}});}'."\n";
962 }
963 else
964 {
965 $code .= 'function request(op,vars){var body={s2member_paypal_checkout_op:op,s2member_paypal_checkout_t:t};for(var k in (vars||{})){if(vars.hasOwnProperty(k))body[k]=vars[k];}return fetch(u,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},body:enc(body)}).then(function(r){return r.json();});}'."\n";
966 $code .= 'function createOrder(){return request("create_order").then(function(res){if(res&&res.order_id)return res.order_id;throw(res ? (res.error || "order_create_failed") : "order_create_failed");});}'."\n";
967 //260928.1703 A completed PayPal capture can reach the verified webhook even when the browser loses its response. Poll only our durable state and submit its saved signed handoff; never issue a second capture on uncertainty.
968 $code .= 'function recoverOrder(n){return request("get_order_status").then(function(res){if(res&&res.fulfilled&&res.rtn_url&&res.rtn_post){postTo(res.rtn_url,res.rtn_post);return;}if(n>=20)throw "order_confirmation_pending";return new Promise(function(resolve){setTimeout(resolve,1200);}).then(function(){return recoverOrder(n+1);});});}'."\n";
969 $code .= 'function onApprove(data){var oid=data&&data.orderID?data.orderID:"";return request("capture_order",{order_id:oid}).catch(function(){return {recoverable:true};}).then(function(res){if(res&&res.rtn_url&&res.rtn_post){postTo(res.rtn_url,res.rtn_post);return;}if(res&&res.recoverable)return recoverOrder(0).catch(function(){showInfo("Payment confirmation is pending. Please do not pay again; check your email or contact support.");});showErr("Payment could not be confirmed. Please contact support before trying again.");});}'."\n";
970 $code .= 'function onCancel(){showInfo("Payment cancelled.");}'."\n";
971 $code .= 'function onError(err){var m="PayPal error. Please try again.";try{if(err){if(typeof err==="string")m="PayPal error: "+err;else if(err.message)m="PayPal error: "+err.message;}}catch(x){}showErr(m);}'."\n";
972 $code .= 'function init(){loadSdk(function(P){var el=document.getElementById(d);if(!el){return;}if(el.getAttribute("data-s2m-ppco-rendered")==="1"){return;}if(!P||!P.Buttons){showErr("PayPal SDK failed to load.");return;}el.setAttribute("data-s2m-ppco-rendered","1");try{P.Buttons({fundingSource:P.FUNDING.PAYPAL,style:{layout:"vertical",tagline:false,height:40},createOrder:createOrder,onApprove:onApprove,onCancel:onCancel,onError:onError}).render("#"+d);}catch(x){el.removeAttribute("data-s2m-ppco-rendered");showErr("PayPal render failed.");}});}'."\n";
973 }
974 $code .= 'if(document.readyState==="complete"){init();}else{window.addEventListener("load",init);}'."\n";
975 $code .= '})();'."\n";
976 $code .= '</script>'."\n";
977 $_code = $code;
978
979 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
980 do_action("ws_plugin__s2member_during_sc_paypal_button", get_defined_vars ());
981 unset($__refs, $__v);
982
983 $code = c_ws_plugin__s2member_sc_paypal_button_e::sc_paypal_button_encryption ($code, get_defined_vars ());
984 return apply_filters("ws_plugin__s2member_sc_paypal_button", $code, get_defined_vars ());
985 }
986
987 $code = trim (c_ws_plugin__s2member_utilities::evl (file_get_contents (dirname (dirname (__FILE__)) . "/templates/buttons/paypal-checkout-button.php")));
988 $code = preg_replace ("/%%images%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . "/src/images")), $code);
989 $code = preg_replace ("/%%wpurl%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr (home_url ())), $code);
990
991 $code = preg_replace ("/%%endpoint%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")), $code);
992 $code = preg_replace ("/%%paypal_business%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"])), $code);
993 $code = preg_replace ("/%%paypal_merchant_id%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_merchant_id"])), $code);
994 $code = preg_replace ("/%%level_label%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["level" . $attr["level"] . "_label"])), $code);
995 $code = preg_replace ("/%%cancel_return%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr (home_url ("/"))), $code); // This brings them back to Front Page.
996 $code = preg_replace ("/%%notify_url%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr (home_url ("/?s2member_paypal_notify=1", $force_notify_url_scheme))), $code);
997 $code = preg_replace ("/%%return%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($success_return_url)), $code);
998 $code = preg_replace ("/%%custom%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["custom"])), $code);
999 $code = preg_replace ("/%%level%%/", c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["level"])), $code);
1000
1001 $code = preg_replace ('/ \<\!--(\<input type\="hidden" name\="(amount|src|srt|sra|a1|p1|t1|a3|p3|t3)" value\="(.*?)" \/\>)--\>/', " $1", $code);
1002 $code = ($attr["rr"] === "BN") ? preg_replace ('/ (\<input type\="hidden" name\="cmd" value\=")(.*?)(" \/\>)/', " $1_xclick$3", $code) : $code;
1003 $code = ($attr["rr"] === "BN") ? preg_replace ('/ (\<input type\="hidden" name\="(src|srt|sra|a1|p1|t1|a3|p3|t3)" value\="(.*?)" \/\>)/', " <!--$1-->", $code) : $code;
1004 $code = ($attr["rr"] === "BN" || !$attr["tp"]) ? preg_replace ('/ (\<input type\="hidden" name\="(a1|p1|t1)" value\="(.*?)" \/\>)/', " <!--$1-->", $code) : $code;
1005 $code = ($attr["rr"] !== "BN") ? preg_replace ('/ (\<input type\="hidden" name\="cmd" value\=")(.*?)(" \/\>)/', " $1_xclick-subscriptions$3", $code) : $code;
1006 $code = ($attr["rr"] !== "BN") ? preg_replace ('/ (\<input type\="hidden" name\="amount" value\="(.*?)" \/\>)/', " <!--$1-->", $code) : $code;
1007
1008 $code = preg_replace ('/ name\="lc" value\="(.*?)"/', ' name="lc" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["lc"])) . '"', $code);
1009 $code = preg_replace ('/ name\="no_shipping" value\="(.*?)"/', ' name="no_shipping" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["ns"])) . '"', $code);
1010 $code = preg_replace ('/ name\="item_name" value\="(.*?)"/', ' name="item_name" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["desc"])) . '"', $code);
1011 $code = preg_replace ('/ name\="item_number" value\="(.*?)"/', ' name="item_number" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["level_ccaps_eotper"])) . '"', $code);
1012 $code = preg_replace ('/ name\="page_style" value\="(.*?)"/', ' name="page_style" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["ps"])) . '"', $code);
1013 $code = preg_replace ('/ name\="currency_code" value\="(.*?)"/', ' name="currency_code" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["cc"])) . '"', $code);
1014 $code = preg_replace ('/ name\="custom" value\="(.*?)"/', ' name="custom" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["custom"])) . '"', $code);
1015
1016 $code = preg_replace ('/ name\="invoice" value\="(.*?)"/', ' name="invoice" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_invoice_input_value)) . '"', $code);
1017
1018 $code = preg_replace ('/ name\="on0" value\="(.*?)"/', ' name="on0" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_on0_input_value)) . '"', $code);
1019 $code = preg_replace ('/ name\="os0" value\="(.*?)"/', ' name="os0" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_os0_input_value)) . '"', $code);
1020 $code = preg_replace ('/ name\="on1" value\="(.*?)"/', ' name="on1" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_on1_input_value)) . '"', $code);
1021 $code = preg_replace ('/ name\="os1" value\="(.*?)"/', ' name="os1" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($paypal_os1_input_value)) . '"', $code);
1022
1023 $code = preg_replace ('/ name\="modify" value\="(.*?)"/', ' name="modify" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["modify"])) . '"', $code);
1024
1025 $code = preg_replace ('/ name\="amount" value\="(.*?)"/', ' name="amount" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["ra"])) . '"', $code);
1026
1027 $code = preg_replace ('/ name\="src" value\="(.*?)"/', ' name="src" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["rr"])) . '"', $code);
1028 $code = preg_replace ('/ name\="srt" value\="(.*?)"/', ' name="srt" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["rrt"])) . '"', $code);
1029 $code = preg_replace ('/ name\="sra" value\="(.*?)"/', ' name="sra" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["rra"])) . '"', $code);
1030
1031 $code = preg_replace ('/ name\="a1" value\="(.*?)"/', ' name="a1" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["ta"])) . '"', $code);
1032 $code = preg_replace ('/ name\="p1" value\="(.*?)"/', ' name="p1" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["tp"])) . '"', $code);
1033 $code = preg_replace ('/ name\="t1" value\="(.*?)"/', ' name="t1" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["tt"])) . '"', $code);
1034 $code = preg_replace ('/ name\="a3" value\="(.*?)"/', ' name="a3" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["ra"])) . '"', $code);
1035 $code = preg_replace ('/ name\="p3" value\="(.*?)"/', ' name="p3" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["rp"])) . '"', $code);
1036 $code = preg_replace ('/ name\="t3" value\="(.*?)"/', ' name="t3" value="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["rt"])) . '"', $code);
1037
1038 $code = $_code = ($attr["image"] && $attr["image"] !== "default") ? preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($attr["image"])) . '"', $code) : preg_replace ('/ src\="(.*?)"/', ' src="' . c_ws_plugin__s2member_utils_strings::esc_refs (esc_attr ($default_image)) . '"', $code);
1039
1040 $code = ($attr["output"] === "anchor") ? '<a href="' . esc_attr (c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code)) . '"><img src="' . esc_attr (($attr["image"] && $attr["image"] !== "default") ? $attr["image"] : $default_image) . '" style="width:auto; height:auto; border:0;" alt="PayPal" /></a>' : $code;
1041 $code = ($attr["output"] === "url") ? c_ws_plugin__s2member_utils_forms::form_whips_2_url ($code) : $code;
1042
1043 foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
1044 ($attr["modify"]) ? do_action("ws_plugin__s2member_during_sc_paypal_modification_button", get_defined_vars ()) : do_action("ws_plugin__s2member_during_sc_paypal_button", get_defined_vars ());
1045 unset($__refs, $__v);
1046 }
1047 $code = c_ws_plugin__s2member_sc_paypal_button_e::sc_paypal_button_encryption ($code, get_defined_vars ());
1048
1049 return apply_filters("ws_plugin__s2member_sc_paypal_button", $code, get_defined_vars ());
1050 }
1051 }
1052 }
1053