diff --git a/inc/class-registration.php b/inc/class-registration.php
index 34b4aca87..7e9796229 100644
--- a/inc/class-registration.php
+++ b/inc/class-registration.php
@@ -512,10 +512,6 @@ function() {
),
)
);
-
- if ( Pro::is_pro_active() ) {
- add_action( 'wp_footer', array( $this, 'test_add_temp_save' ) );
- }
}
if ( ! self::$scripts_loaded['google-map'] && has_block( 'themeisle-blocks/google-map', $post ) ) {
@@ -966,31 +962,6 @@ public static function sticky_style() {
echo '';
}
- /**
- * Add inline script for temporary save mode.
- *
- * @static
- * @access public
- */
- public static function test_add_temp_save() {
-
- /**
- * In this function we add a script that will activate the temporary save mode.
- * This will be for the Pro users. This will be removed in the future and moved to the Pro plugin.
- */
-
- if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
- return;
- }
-
- echo "";
- }
-
/**
* Get the content of all active widgets.
*
diff --git a/inc/integrations/api/form-request-data.php b/inc/integrations/api/form-request-data.php
index 8d1b6a2f3..67bfbd49f 100644
--- a/inc/integrations/api/form-request-data.php
+++ b/inc/integrations/api/form-request-data.php
@@ -679,6 +679,15 @@ public function mark_as_duplicate() {
$this->set_saving_mode( 'duplicate' );
}
+ /**
+ * Mark as temporary data.
+ *
+ * @return void
+ */
+ public function mark_as_temporary_data() {
+ $this->set_saving_mode( 'temporary' );
+ }
+
/**
* Dump the data. Can be used to reconstruct the object.
*
@@ -740,4 +749,14 @@ public function append_metadata( $response ) {
}
}
}
+
+ /**
+ * Check if field is present in the metadata.
+ *
+ * @param string $key The key.
+ * @return bool
+ */
+ public function has_metadata( $key ) {
+ return isset( $this->metadata[ $key ] );
+ }
}
diff --git a/inc/integrations/api/form-response-data.php b/inc/integrations/api/form-response-data.php
index 3aefc4f46..01c30360c 100644
--- a/inc/integrations/api/form-response-data.php
+++ b/inc/integrations/api/form-response-data.php
@@ -59,6 +59,11 @@ class Form_Data_Response {
const ERROR_PROVIDER_DUPLICATED_EMAIL = '208';
const ERROR_PROVIDER_CREDENTIAL_ERROR = '209';
const ERROR_WEBHOOK_COULD_NOT_TRIGGER = '210';
+ const ERROR_RUNTIME_STRIPE_SESSION_VALIDATION = '300';
+ const ERROR_STRIPE_CHECKOUT_SESSION_CREATION = '301';
+ const ERROR_STRIPE_CHECKOUT_SESSION_NOT_FOUND = '302';
+ const ERROR_STRIPE_PAYMENT_UNPAID = '303';
+ const ERROR_STRIPE_METADATA_RECORD_NOT_FOUND = '304';
/**
@@ -368,6 +373,11 @@ public static function get_error_code_message( $error_code ) {
self::ERROR_FILE_MISSING_BINARY => __( 'The file data is missing.', 'otter-blocks' ),
self::ERROR_WEBHOOK_COULD_NOT_TRIGGER => __( 'The webhook could not be triggered.', 'otter-blocks' ),
self::ERROR_MISSING_DUMP_DATA => __( 'The form dump data is missing.', 'otter-blocks' ),
+ self::ERROR_STRIPE_CHECKOUT_SESSION_CREATION => __( 'The Stripe Checkout session could not be created.', 'otter-blocks' ),
+ self::ERROR_STRIPE_CHECKOUT_SESSION_NOT_FOUND => __( 'The Stripe Checkout session was not found.', 'otter-blocks' ),
+ self::ERROR_STRIPE_PAYMENT_UNPAID => __( 'The payment was not completed.', 'otter-blocks' ),
+ self::ERROR_STRIPE_METADATA_RECORD_NOT_FOUND => __( 'The metadata submission record was not found.', 'otter-blocks' ),
+ self::ERROR_RUNTIME_STRIPE_SESSION_VALIDATION => __( 'The payment has been processed. You will be contacted by the support team.', 'otter-blocks' ),
);
if ( ! isset( $error_messages[ $error_code ] ) ) {
diff --git a/inc/server/class-form-server.php b/inc/server/class-form-server.php
index 745cb7e30..e9af9bde7 100644
--- a/inc/server/class-form-server.php
+++ b/inc/server/class-form-server.php
@@ -17,6 +17,7 @@
use ThemeIsle\GutenbergBlocks\Integration\Form_Utils;
use ThemeIsle\GutenbergBlocks\Integration\Mailchimp_Integration;
use ThemeIsle\GutenbergBlocks\Integration\Sendinblue_Integration;
+use ThemeIsle\GutenbergBlocks\Plugins\Stripe_API;
use ThemeIsle\GutenbergBlocks\Pro;
use WP_Error;
use WP_HTTP_Response;
@@ -187,7 +188,7 @@ public function register_routes() {
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'confirm_form' ),
'permission_callback' => function ( $request ) {
- $session = $request->get_param( 'session' );
+ $session = $request->get_param( 'stripe_session_id' );
if ( apply_filters( 'otter_form_session_confirmation', $session ) ) {
return __return_true();
@@ -332,15 +333,12 @@ public function frontend( $request ) {
*/
public function confirm_form( $request ) {
- $record_id = $request->get_param( 'record_id' );
- $response = new Form_Data_Response();
+ $response = new Form_Data_Response();
try {
- if ( ! empty( $record_id ) ) {
- $response = apply_filters( 'otter_form_record_confirm', $response, $request );
- }
+ $response = apply_filters( 'otter_form_record_confirm', $response, $request );
} catch ( Exception $e ) {
- $response->set_code( Form_Data_Response::ERROR_RUNTIME_ERROR );
+ $response->set_code( Form_Data_Response::ERROR_RUNTIME_STRIPE_SESSION_VALIDATION );
$response->add_reason( $e->getMessage() );
} finally {
return $response->build_response();
@@ -1032,7 +1030,7 @@ public static function pull_fields_options_for_form( $form_data ) {
foreach ( $required_fields as $required_field ) {
foreach ( $global_fields_options as $field ) {
if ( isset( $field['fieldOptionName'] ) && $field['fieldOptionName'] === $required_field ) {
- $new_field = new Form_Field_WP_Option_Data( $field_name, $field['fieldOptionType'] );
+ $new_field = new Form_Field_WP_Option_Data( $required_field, $field['fieldOptionType'] );
if ( isset( $field['options'] ) ) {
$new_field->set_options( $field['options'] );
}
@@ -1055,8 +1053,7 @@ public static function pull_fields_options_for_form( $form_data ) {
* @return bool
*/
public function verify_confirmation_session( $session ) {
- // TODO: Add verification for Stripe session when adding the stripe field.
- return 'test_123' === $session; // Test ONLY.
+ return ! empty( $session ) && is_string( $session );
}
/**
* The instance method for the static class.
diff --git a/plugins/otter-pro/inc/plugins/class-form-emails-storing.php b/plugins/otter-pro/inc/plugins/class-form-emails-storing.php
index 5f1154013..617063f2c 100644
--- a/plugins/otter-pro/inc/plugins/class-form-emails-storing.php
+++ b/plugins/otter-pro/inc/plugins/class-form-emails-storing.php
@@ -10,6 +10,7 @@
use ThemeIsle\GutenbergBlocks\Integration\Form_Data_Request;
use ThemeIsle\GutenbergBlocks\Integration\Form_Data_Response;
use ThemeIsle\GutenbergBlocks\Integration\Form_Settings_Data;
+use ThemeIsle\GutenbergBlocks\Plugins\Stripe_API;
use ThemeIsle\GutenbergBlocks\Server\Form_Server;
use WP_Post;
use WP_Query;
@@ -46,7 +47,6 @@ public function init() {
add_action( 'init', array( $this, 'create_form_records_type' ) );
add_action( 'admin_init', array( $this, 'set_form_records_cap' ), 10, 0 );
add_action( 'otter_form_after_submit', array( $this, 'store_form_record' ) );
- add_action( 'otter_form_after_submit', array( $this, 'test_redirect_link_with_record_id' ) );
add_action( 'admin_head', array( $this, 'add_style' ) );
@@ -288,7 +288,7 @@ public function store_form_record( $form_data ) {
add_post_meta( $post_id, self::FORM_RECORD_META_KEY, $meta );
- $form_data->metadata['record_id'] = $post_id;
+ $form_data->metadata['otter_form_record_id'] = $post_id;
return $form_data;
}
@@ -1120,7 +1120,31 @@ private function format_based_on_status( $content, $status ) {
*/
public function confirm_submission( $response, $request ) {
- $record_id = $request->get_param( 'record_id' );
+ $session_id = $request->get_param( 'stripe_session_id' );
+
+ $stripe = new Stripe_API();
+
+ $stripe_response = $stripe->create_request( 'get_session', $session_id );
+
+ if ( is_wp_error( $stripe_response ) ) {
+ $response->set_code( Form_Data_Response::ERROR_STRIPE_CHECKOUT_SESSION_NOT_FOUND );
+ return $response;
+ }
+
+ $is_paid = 'paid' === $stripe_response->payment_status;
+
+ if ( ! $is_paid ) {
+ $response->set_code( Form_Data_Response::ERROR_STRIPE_PAYMENT_UNPAID );
+ return $response;
+ }
+
+ $record_id = $stripe_response->metadata['otter_form_record_id'];
+
+ if ( empty( $record_id ) ) {
+ $response->set_code( Form_Data_Response::ERROR_STRIPE_METADATA_RECORD_NOT_FOUND );
+ return $response;
+ }
+
$post_status = get_post_status( $record_id );
// If the post status is not 'draft', then the submission has already been confirmed.
@@ -1129,6 +1153,7 @@ public function confirm_submission( $response, $request ) {
$response->mark_as_success();
return $response;
}
+
$meta = get_post_meta( $record_id, self::FORM_RECORD_META_KEY, true );
if ( ! isset( $meta['dump'] ) || empty( $meta['dump']['value'] ) ) {
@@ -1149,15 +1174,14 @@ public function confirm_submission( $response, $request ) {
( ! class_exists( 'ThemeIsle\GutenbergBlocks\Integration\Form_Data_Request' ) ) ||
! ( $form_data instanceof \ThemeIsle\GutenbergBlocks\Integration\Form_Data_Request )
) {
-
- $response->set_code( $form_data->get_error_code() );
+ $response->set_code( Form_Data_Response::ERROR_RUNTIME_STRIPE_SESSION_VALIDATION );
return $response;
}
do_action( 'otter_form_after_submit', $form_data );
if ( $form_data->has_error() ) {
- $response->set_code( $form_data->get_error_code() );
+ $response->set_code( Form_Data_Response::ERROR_RUNTIME_STRIPE_SESSION_VALIDATION );
return $response;
}
@@ -1174,46 +1198,6 @@ public function confirm_submission( $response, $request ) {
return $response;
}
- /**
- * Test redirect link with record id.
- *
- * @param Form_Data_Request|null $form_data The form data.
- */
- public function test_redirect_link_with_record_id( $form_data ) {
-
- /**
- * In this manner things like Stripe confirmation link will work.
- */
-
- if ( ! isset( $form_data ) ) {
- return $form_data;
- }
-
- if (
- ( ! class_exists( 'ThemeIsle\GutenbergBlocks\Integration\Form_Data_Request' ) ) ||
- ! ( $form_data instanceof \ThemeIsle\GutenbergBlocks\Integration\Form_Data_Request ) ||
- $form_data->has_error() ||
- ! $form_data->is_temporary_data()
- ) {
- return $form_data;
- }
-
- /**
- * If the `record_id` and `stripe_payment_intent` (to be added in future PR) are set, then we can generate the confirmation link.
- */
- if ( array_key_exists( 'record_id', $form_data->metadata ) ) {
- $form_data->metadata['frontend_external_confirmation_url'] = add_query_arg(
- array(
- 'record_id' => $form_data->metadata['record_id'], // TODO: Test ONLY. This will will be extracted from Stripe payment intent metadata.
- 'session' => 'test_123',
- ),
- $form_data->get_payload_field( 'postUrl' )
- );
- }
-
- return $form_data;
- }
-
/**
* The instance method for the static class.
* Defines and returns the instance of the static class.
diff --git a/plugins/otter-pro/inc/plugins/class-form-pro-features.php b/plugins/otter-pro/inc/plugins/class-form-pro-features.php
index 8d2ddbefe..ed833476c 100644
--- a/plugins/otter-pro/inc/plugins/class-form-pro-features.php
+++ b/plugins/otter-pro/inc/plugins/class-form-pro-features.php
@@ -33,10 +33,12 @@ public function init() {
if ( License::has_active_license() ) {
add_filter( 'otter_form_data_preparation', array( $this, 'save_files_to_uploads' ) );
add_filter( 'otter_form_data_preparation', array( $this, 'load_files_to_media_library' ) );
+ add_filter( 'otter_form_data_preparation', array( $this, 'mark_request_with_stripe_as_temp' ), 0 );
+
add_action( 'otter_form_after_submit', array( $this, 'clean_files_from_uploads' ) );
add_action( 'otter_form_after_submit', array( $this, 'send_autoresponder' ), 99 );
add_action( 'otter_form_after_submit', array( $this, 'trigger_webhook' ) );
- add_action( 'otter_form_after_submit', array( $this, 'create_stripe_session' ) );
+ add_action( 'otter_form_after_submit', array( $this, 'create_stripe_session' ), 50 );
}
}
@@ -515,10 +517,40 @@ public function replace_magic_tags( $content, $form_inputs ) {
return $content;
}
+ /**
+ * Mark request with Stripe as temp.
+ *
+ * @param Form_Data_Request|null $form_data The form data.
+ */
+ public function mark_request_with_stripe_as_temp( $form_data ) {
+ if ( ! isset( $form_data ) ) {
+ return $form_data;
+ }
+
+ if (
+ ( ! class_exists( 'ThemeIsle\GutenbergBlocks\Integration\Form_Data_Request' ) ) ||
+ ! ( $form_data instanceof \ThemeIsle\GutenbergBlocks\Integration\Form_Data_Request ) ||
+ $form_data->has_error()
+ ) {
+ return $form_data;
+ }
+
+ $fields_options = $form_data->get_wp_fields_options();
+
+ foreach ( $fields_options as $field ) {
+ if ( $field->has_type() && 'stripe' === $field->get_type() ) {
+ $form_data->mark_as_temporary_data();
+ break;
+ }
+ }
+
+ return $form_data;
+ }
+
/**
* Create a Stripe session.
*
- * @param Form_Data_Request $form_data The form data.
+ * @param Form_Data_Request|null $form_data The form data.
*/
public function create_stripe_session( $form_data ) {
if ( ! isset( $form_data ) ) {
@@ -528,11 +560,16 @@ public function create_stripe_session( $form_data ) {
if (
( ! class_exists( 'ThemeIsle\GutenbergBlocks\Integration\Form_Data_Request' ) ) ||
! ( $form_data instanceof \ThemeIsle\GutenbergBlocks\Integration\Form_Data_Request ) ||
- $form_data->has_error()
+ $form_data->has_error() ||
+ $form_data->is_duplicate()
) {
return $form_data;
}
+ if ( ! $form_data->has_metadata( 'otter_form_record_id' ) ) {
+ return $form_data;
+ }
+
$has_stripe = false;
$fields_options = $form_data->get_wp_fields_options();
@@ -581,11 +618,6 @@ public function create_stripe_session( $form_data ) {
$payload['success_url'] = $permalink;
$payload['cancel_url'] = $permalink;
- $customer_email = $form_data->get_email_from_form_input();
- if ( ! empty( $customer_email ) ) {
- $payload['customer_email'] = $customer_email;
- }
-
// Prepare the line items for the Stripe session request.
$line_items = array();
foreach ( $products_to_process as $product ) {
@@ -604,6 +636,8 @@ public function create_stripe_session( $form_data ) {
foreach ( $raw_metadata as $key => $value ) {
$metadata[ mb_substr( $key, 0, 40 ) ] = mb_substr( wp_json_encode( $value ), 0, 500 );
}
+ $metadata['otter_form_record_id'] = $form_data->metadata['otter_form_record_id'];
+
$payload['metadata'] = $metadata;
$stripe = new Stripe_API();
@@ -613,6 +647,12 @@ public function create_stripe_session( $form_data ) {
$payload
);
+ if ( is_wp_error( $session ) ) {
+ $form_data->set_error( Form_Data_Response::ERROR_STRIPE_CHECKOUT_SESSION_CREATION );
+ return $form_data;
+ }
+
+ $form_data->metadata['frontend_external_confirmation_url'] = $session->url;
return $form_data;
}
diff --git a/src/blocks/frontend/form/index.js b/src/blocks/frontend/form/index.js
index a03a1390c..92074a25e 100644
--- a/src/blocks/frontend/form/index.js
+++ b/src/blocks/frontend/form/index.js
@@ -8,27 +8,26 @@ import { domReady } from '../../helpers/frontend-helper-functions.js';
let startTimeAntiBot = null;
let METADATA_VERSION = 1;
-window.saveMode = 'permanent';
+let saveMode = 'permanent';
-const hasRecordId = () => {
+const hasStripeConfirmation = () => {
const urlParams = new URLSearchParams( window.location.search );
- return urlParams.has( 'record_id' );
+ return urlParams.has( 'stripe_session_id' );
};
const confirmRecord = async() => {
// Get the record id from the URL
const urlParams = new URLSearchParams( window.location.search );
- const recordId = urlParams.get( 'record_id' ); // TODO: test ONLY. This will be extracted from Stripe.
- const session = urlParams.get( 'session' );
+ const stripeSessionId = urlParams.get( 'stripe_session_id' );
- console.log( 'Record ID: ' + recordId ); // TODO: remove after QA.
+ console.log( 'Session ID: ' + stripeSessionId ); // TODO: remove after QA.
const formURlEndpoint = ( window?.themeisleGutenbergForm?.root || ( window.location.origin + '/wp-json/' ) ) + 'otter/v1/form/confirm';
console.log( 'Making a request for ' + formURlEndpoint ); // TODO: remove after QA.
- return await fetch( formURlEndpoint + `?record_id=${recordId}&session=${session}`, {
+ return await fetch( formURlEndpoint + `?stripe_session_id=${stripeSessionId}`, {
method: 'GET',
credentials: 'include'
});
@@ -144,6 +143,7 @@ const extractFormFields = async( form ) => {
metadata = {
fieldOptionName: input?.dataset?.fieldOptionName
};
+ saveMode = 'temporary';
} else {
const labels = input.querySelectorAll( '.o-form-multiple-choice-field > label' );
const valuesElem = input.querySelectorAll( '.o-form-multiple-choice-field > input' );
@@ -302,8 +302,6 @@ const getCurrentPostId = () => {
const handleAfterSubmit = ( request, displayMsg, onSuccess, onFail, onCleanUp ) => {
request.then( r => r.json() ).then( response => {
- console.log( response );
-
/**
* @type {import('./types.js').IFormResponse}
*/
@@ -456,7 +454,7 @@ const collectAndSendInputFormData = async( form, btn, displayMsg ) => {
method: 'POST',
headers: {
'X-WP-Nonce': window?.themeisleGutenbergForm?.nonce,
- 'O-Form-Save-Mode': window.saveMode
+ 'O-Form-Save-Mode': saveMode
},
credentials: 'include',
body: formData
@@ -547,7 +545,7 @@ domReady( () => {
const sendBtn = form.querySelector( 'button' );
const displayMsg = new DisplayFormMessage( form );
- if ( hasRecordId() ) {
+ if ( hasStripeConfirmation() ) {
sendBtn.disabled = true;
const btnText = sendBtn.innerHTML;