${error}`);
+ })
+ },
+
+/*
+
+ async onApprove(data, actions) {
+ try {
+ const response = await fetch(`/api/orders/${data.orderID}/capture`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+
+ const orderData = await response.json();
+ // Three cases to handle:
+ // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
+ // (2) Other non-recoverable errors -> Show a failure message
+ // (3) Successful transaction -> Show confirmation or thank you message
+
+ const errorDetail = orderData?.details?.[0];
+
+ if (errorDetail?.issue === "INSTRUMENT_DECLINED") {
+ // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
+ // recoverable state, per https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/
+ return actions.restart();
+ } else if (errorDetail) {
+ // (2) Other non-recoverable errors -> Show a failure message
+ throw new Error(`${errorDetail.description} (${orderData.debug_id})`);
+ } else if (!orderData.purchase_units) {
+ throw new Error(JSON.stringify(orderData));
+ } else {
+ // (3) Successful transaction -> Show confirmation or thank you message
+ // Or go to another URL: actions.redirect('thank_you.html');
+ const transaction =
+ orderData?.purchase_units?.[0]?.payments?.captures?.[0] ||
+ orderData?.purchase_units?.[0]?.payments?.authorizations?.[0];
+ resultMessage(
+ `Transaction ${transaction.status}: ${transaction.id}
See console for all available details`,
+ );
+ console.log(
+ "Capture result",
+ orderData,
+ JSON.stringify(orderData, null, 2),
+ );
+ }
+ } catch (error) {
+ console.error(error);
+ resultMessage(
+ `Sorry, your transaction could not be processed...
${error}`,
+ );
+ }
+ },
+*/
+})
+.render("#paypal-button-container");
+
+// Example function to show a result to the user. Your site's UI library can be used instead.
+function resultMessage(message) {
+ const container = document.querySelector("#result-message");
+ container.innerHTML = message;
+}
+
diff --git a/plugins/fipfcard_plugin/php/paypal/paypal.php b/plugins/fipfcard_plugin/php/paypal/paypal.php
new file mode 100644
index 0000000..2b53fb2
--- /dev/null
+++ b/plugins/fipfcard_plugin/php/paypal/paypal.php
@@ -0,0 +1,168 @@
+cart;
+ error_log( "cart" );
+ error_log( json_encode( $cart ) );
+ create_order($cart);
+
+ wp_send_json_success(
+ array(
+ 'from paypal_order',
+ "data_received" => $data_received,
+ ),
+ 200
+ );
+}
+add_action( 'wp_ajax_paypal_orders', 'fipfcard_paypal_order' );
+
+
+
+
+
+
+/**
+ * Generate an OAuth 2.0 access token for authenticating with PayPal REST APIs.
+ * @see https://developer.paypal.com/docs/checkout/standard/integrate/#link-integratebackend
+ * @see https://developer.paypal.com/api/rest/authentication/
+ */
+function generate_access_token( )
+{
+ $base = "https://api-m.sandbox.paypal.com";
+
+ try {
+ if ( !PAYPAL_CLIENT_ID || !PAYPAL_CLIENT_SECRET ) {
+ throw new Error( "MISSING_API_CREDENTIALS" );
+ }
+ $credentials = PAYPAL_CLIENT_ID . ":" . PAYPAL_CLIENT_SECRET;
+ $auth = base64_encode($credentials);
+
+ $url = $base . '/v1/oauth2/token';
+ $body = http_build_query(array('grant_type' => 'client_credentials'));
+ // Initialize curl
+ $ch = curl_init();
+ // Set curl options
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array(
+ 'Authorization: Basic ' . $auth,
+ ));
+ // Execute curl and get the response
+ $data_json = curl_exec($ch);
+
+ if ( $data_json === false)
+ throw new Error('cURL error: ' . curl_error($ch));
+ // Close curl
+ curl_close($ch);
+
+ $data = json_decode($data_json);
+
+ return $data->access_token;
+ }
+ catch (Throwable $error) {
+ error_log("Failed to generate Access Token:");
+ error_log($error->getMessage());
+ }
+};
+/*
+*/
+
+
+
+/**
+ * Create an order to start the transaction.
+ * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
+ */
+
+function create_order( $cart )
+{
+
+ // use the cart information passed from the front-end to calculate the purchase unit details
+
+ $access_token = generate_access_token();
+ error_log("access_token:");
+ error_log($access_token);
+
+/*
+
+
+ const url = `${base}/v2/checkout/orders`;
+
+ const payload = {
+
+ intent: "CAPTURE",
+
+ purchase_units: [
+
+ {
+
+ amount: {
+
+ currency_code: "USD",
+
+ value: "100.00",
+
+ },
+
+ },
+
+ ],
+
+ };
+
+
+
+ const response = await fetch(url, {
+
+ headers: {
+
+ "Content-Type": "application/json",
+
+ Authorization: `Bearer ${accessToken}`,
+
+ // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation:
+
+ // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/
+
+ // "PayPal-Mock-Response": '{"mock_application_codes": "MISSING_REQUIRED_PARAMETER"}'
+
+ // "PayPal-Mock-Response": '{"mock_application_codes": "PERMISSION_DENIED"}'
+
+ // "PayPal-Mock-Response": '{"mock_application_codes": "INTERNAL_SERVER_ERROR"}'
+
+ },
+
+ method: "POST",
+
+ body: JSON.stringify(payload),
+
+ });
+
+
+
+ return handleResponse(response);
+
+*/
+};
+
+
+
+?>
diff --git a/plugins/fipfcard_plugin/php/utils/console_log.php b/plugins/fipfcard_plugin/php/utils/console_log.php
index 151aab6..bf18325 100644
--- a/plugins/fipfcard_plugin/php/utils/console_log.php
+++ b/plugins/fipfcard_plugin/php/utils/console_log.php
@@ -4,12 +4,15 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
https://stackify.com/how-to-log-to-console-in-php/
*/
-function console_log($output) {
+function console_log(...$outputs) {
if (FIPFCARD_CONSOLE_OFF)
return;
- $json_output = json_encode($output, JSON_HEX_TAG);
- $js_code = '';
- echo $js_code;
+ foreach($outputs as $output)
+ {
+ $json_output = json_encode($output, JSON_HEX_TAG);
+ $js_code = '';
+ echo $js_code;
+ }
}
diff --git a/plugins/fipfcard_plugin/php/utils/globals.php b/plugins/fipfcard_plugin/php/utils/globals.php
index 14260f2..faafd95 100644
--- a/plugins/fipfcard_plugin/php/utils/globals.php
+++ b/plugins/fipfcard_plugin/php/utils/globals.php
@@ -11,12 +11,28 @@ const CONSOLE_OFF = true;
*/
const FIPFCARD_CONSOLE_OFF = false;
-/* a variable that will contain the name of the first script enqueued
-*/
+/**
+ * a variable that will contain the name of the first script enqueued
+ */
$fipfcard_first_script = null;
-/* path to ajax.js file, from root of js dir
-*/
+
+/**
+ * path to ajax.js file, from root of js dir
+ */
$fipfcard_ajax_file = "utils/ajax.js";
+
+/**
+ *
+ * LIVE :
+const PAYPAL_CLIENT_ID = "Aedn5e8z__hPBvKirqw5bwlhI9ChG8_N6c1xbgybYyBr4B4oP8uVzmVdH1QVKdPQKf6bWg7orPV4PDrO";
+const PAYPAL_CLIENT_SECRET = "EGeGwfHGxHxsjnC-tH8W0IL4nN3_xlc3sXFRPCQOw5uUoWae3eOgghuDKMnZc5DVGTbP6yIjVJ1BaAra";
+ * SANBOX :
+const PAYPAL_CLIENT_ID = "AfcmwxIXlG2ZxaMdjazX57I70BXz__aEqNWaTnqfSCI34a0V7nMbytswx7EViUjlpHs7opyrRwaH9YLl";
+const PAYPAL_CLIENT_SECRET = "EGunIhGRjPvn0Z8wXO0JsdhET30OStTAH_IyRsmhimEN23_qiRSFD-ql4tvnulKJw6TitZ-vU-ytc4A-";
+ */
+const PAYPAL_CLIENT_ID = "AfcmwxIXlG2ZxaMdjazX57I70BXz__aEqNWaTnqfSCI34a0V7nMbytswx7EViUjlpHs7opyrRwaH9YLl";
+const PAYPAL_CLIENT_SECRET = "EGunIhGRjPvn0Z8wXO0JsdhET30OStTAH_IyRsmhimEN23_qiRSFD-ql4tvnulKJw6TitZ-vU-ytc4A-";
+
?>
diff --git a/plugins/fipfcard_plugin/utils/plugin_ajax.js b/plugins/fipfcard_plugin/utils/plugin_ajax.js
index 9b6762c..d80b7ec 100644
--- a/plugins/fipfcard_plugin/utils/plugin_ajax.js
+++ b/plugins/fipfcard_plugin/utils/plugin_ajax.js
@@ -3,9 +3,12 @@
* - PLGNTLS_data.ajax_nonce and PLGNTLS_data.ajax_url
* are passed from the class PLGNTLS_class
*/
+
+/*
+// OLD VERSION
console.log("PLGNTLS_data");
console.log(PLGNTLS_data);
-function PLGNTLS_ajax(data_obj, action) {
+function PLGNTLS_ajax(action, data_obj) {
const data = new FormData();
data.append("action", action);
data.append("_ajax_nonce", PLGNTLS_data.ajax_nonce);
@@ -15,6 +18,101 @@ function PLGNTLS_ajax(data_obj, action) {
return fetch(PLGNTLS_data.ajax_url, {
method: "POST",
credentials: "same-origin",
- body: data
+ body: data,
});
}
+*/
+
+// https://stackoverflow.com/q/52657814/9497573
+function is_plain_object(obj)
+{
+ if (!obj)
+ return false;
+ if (obj.constructor !== Object)
+ return false;
+ if (Object.getPrototypeOf(obj) !== Object.prototype)
+ return false;
+ return true;
+}
+
+function PLGNTLS_fetch(src = null, options = null)
+{
+ if (src === null)
+ return null;
+ if (options === null)
+ {
+ const data = new FormData();
+ data.append('action', src);
+ data.append('_ajax_nonce', PLGNTLS_data.ajax_nonce);
+
+ options = {
+ method: 'POST',
+ credentials: 'same-origin',
+ body: data,
+ };
+ }
+ else if (is_plain_object(options))
+ {
+ // check for method, default POST
+ if (!Object.hasOwn(options, 'method'))
+ options.method = 'POST';
+ // check for credentials, default same-origin
+ if (!Object.hasOwn(options, 'credentials'))
+ options.credentials = 'same-origin';
+
+ // check for body, default contains action and nonce
+ if (!Object.hasOwn(options, 'body'))
+ options.body = new FormData();
+ // add action and nonce in options.body
+ if (options.body instanceof FormData)
+ {
+ // dont check if action and nonce already exist, need new anyway
+ options.body.set('action', src);
+ options.body.set('_ajax_nonce', PLGNTLS_data.ajax_nonce);
+ }
+ else
+ {
+ // should think a better strategy : https://stackoverflow.com/q/20295080/9497573
+ // const data = {};
+ // if (is_plain_object(options.body))
+ // {
+ // for (const key in options.body)
+ // data[key] = options.body[key];
+ // }
+ // else
+ // data.data = options.body;
+ // data.action = src;
+ // data._ajax_nonce = PLGNTLS_data.ajax_nonce;
+ // options.body = JSON.stringify(data);
+
+ // cannot work if fetch use :
+ // headers: {"Content-Type": "application/json"},
+ const data = new FormData( );
+ data.append( 'action', src );
+ data.append( '_ajax_nonce', PLGNTLS_data.ajax_nonce );
+ if ( is_plain_object( options.body ) )
+ {
+ console.log( "1" );
+ for ( const key in options.body )
+ data.append( key, JSON.stringify(options.body[key]) );
+ }
+ // is string : https://stackoverflow.com/q/4059147/9497573
+ else if ( typeof options.body === 'string' || options.body instanceof String )
+ {
+ console.log( "2" );
+ data.append( 'data', options.body );
+ }
+ else
+ {
+ console.log( "3" );
+ data.append('data', JSON.stringify(options.body));
+ }
+ options.body = data;
+ }
+ }
+ else
+ throw new Error('options not plain object or formData');
+
+ console.log("options: ", options);
+ return fetch(PLGNTLS_data.ajax_url, options);
+}
diff --git a/plugins/fipfcard_plugin/utils/plugin_tools.php b/plugins/fipfcard_plugin/utils/plugin_tools.php
index 9a0f95d..0febca2 100644
--- a/plugins/fipfcard_plugin/utils/plugin_tools.php
+++ b/plugins/fipfcard_plugin/utils/plugin_tools.php
@@ -54,10 +54,13 @@ class PLGNTLS_class
public function add_to_front($scripts_arr = null, $vars = null) {
if (!is_null($scripts_arr))
{
+ console_log("in is null scripts_arr");
// add ajax file at beginning of files list
array_unshift($scripts_arr, "utils/plugin_ajax.js");
$nonce = array("ajax_nonce" => wp_create_nonce('wp-pageviews-nonce'));
$url = array("ajax_url" => admin_url('admin-ajax.php'));
+ if (!is_array($vars))
+ $vars = array();
$vars = array_merge($vars, $nonce);
$vars = array_merge($vars, $url);
}
@@ -68,6 +71,9 @@ class PLGNTLS_class
}
if (!is_null($scripts_arr))
$this->add_scripts_to_front($scripts);
+
+ console_log("vars:");
+ console_log($vars);
if (!is_null($vars))
$this->add_vars_to_front($vars);
return $this->create_html($scripts, $vars);
@@ -248,8 +254,6 @@ class PLGNTLS_class
else
$script->basename = pathinfo($script_name, PATHINFO_BASENAME);
$script->handle = "PLGNTLS_" . str_replace(".", "_", $script->basename);
- console_log("script->handle:");
- console_log($script->handle);
if ($script->ext === "url") {
$script->url = $script_name;
diff --git a/private b/private
index 42499ed..d4c3e0c 160000
--- a/private
+++ b/private
@@ -1 +1 @@
-Subproject commit 42499ed5b473b3a849c7f26d9152f295ee9b239c
+Subproject commit d4c3e0c142cc62c878e97fbc5d3c7633688c48df