is_payable_form_page( $page_id ) ) { return false; } // First, try to get from transient (fastest). $transient_key = 'bp_block_settings_' . $page_id . '_' . $widget_id; $settings = get_transient( $transient_key ); if ( ! empty( $settings ) && is_array( $settings ) ) { return $settings; } // Transient not found - parse block from post content. // This handles cases where the page is cached. $settings = $this->parse_block_settings_from_post( $page_id, $widget_id ); if ( ! empty( $settings ) && is_array( $settings ) ) { // Cache in transient for future requests. set_transient( $transient_key, $settings, HOUR_IN_SECONDS ); return $settings; } return false; } /** * Parse block settings directly from post content. * * This method finds the Better Payment block in the post content and extracts its attributes. * Similar to how Elementor's get_elementor_widget_settings works. * * @param int $page_id The page ID. * @param string $widget_id The widget/block ID (blockId attribute). * @return array|false The block settings or false if not found. */ private function parse_block_settings_from_post( $page_id, $widget_id ) { $post = get_post( $page_id ); if ( ! $post || empty( $post->post_content ) ) { return false; } // Parse blocks from post content. $blocks = parse_blocks( $post->post_content ); // Find the Better Payment block with matching blockId. $block_attributes = $this->find_payment_block_recursive( $blocks, $widget_id ); if ( empty( $block_attributes ) ) { return false; } // Get global settings. $global_settings = \Better_Payment\Lite\Admin\DB::get_settings(); // Build settings using BlockManager's method. $form_layout = ! empty( $block_attributes['formLayout'] ) ? $block_attributes['formLayout'] : 'layout-1'; $settings = BlockManager::get_instance()->build_block_settings( $block_attributes, $global_settings, $form_layout ); return $settings; } /** * Recursively find a Better Payment block with matching blockId. * * @param array $blocks Array of parsed blocks. * @param string $widget_id The blockId to find. * @return array|false Block attributes or false if not found. */ private function find_payment_block_recursive( $blocks, $widget_id ) { foreach ( $blocks as $block ) { // Check if this is a Better Payment block with matching blockId. if ( 'better-payment/payment-form' === $block['blockName'] ) { $block_id = isset( $block['attrs']['blockId'] ) ? $block['attrs']['blockId'] : ''; if ( $block_id === $widget_id ) { return $block['attrs']; } } // Check inner blocks. if ( ! empty( $block['innerBlocks'] ) ) { $found = $this->find_payment_block_recursive( $block['innerBlocks'], $widget_id ); if ( $found ) { return $found; } } } return false; } /** * Check if this is a block form submission. * * @param int $page_id The page ID. * @param string $widget_id The widget/block ID. * @return bool True if this is a block form, false otherwise. */ private function is_block_form( $page_id, $widget_id ) { $settings = $this->get_block_settings( $page_id, $widget_id ); return ! empty( $settings ) && is_array( $settings ); } /** * Handle PayPal form submission for Gutenberg blocks. * * This intercepts the form submission before the Elementor handler. * If settings are found in transient (block form), process here. * Otherwise, return and let the Elementor handler process it. * * @since 1.0.0 */ public function block_paypal_form_handle() { // phpcs:disable WordPress.Security.NonceVerification.Missing // Bail immediately if not a Gutenberg block submission — zero DB overhead for Elementor forms. if ( empty( $_POST['better_payment_source'] ) || 'gutenberg' !== $_POST['better_payment_source'] ) { return; } // phpcs:enable WordPress.Security.NonceVerification.Missing // Verify nonce. if ( ! check_admin_referer( 'better-payment-paypal', 'security' ) ) { return; } // phpcs:disable WordPress.Security.NonceVerification.Missing $page_id = ! empty( $_POST['better_payment_page_id'] ) ? intval( $_POST['better_payment_page_id'] ) : 0; $widget_id = ! empty( $_POST['better_payment_widget_id'] ) ? sanitize_text_field( $_POST['better_payment_widget_id'] ) : ''; // phpcs:enable WordPress.Security.NonceVerification.Missing if ( empty( $page_id ) || empty( $widget_id ) ) { return; // Let the original handler deal with missing data. } // Check if this is a block form by looking for transient settings. if ( ! $this->is_block_form( $page_id, $widget_id ) ) { return; // Not a block form, let Elementor handler process it. } // This is a block form - handle the payment here. $this->process_paypal_payment( $page_id, $widget_id ); } /** * Process PayPal payment for block forms. * * @param int $page_id The page ID. * @param string $widget_id The widget/block ID. */ private function process_paypal_payment( $page_id, $widget_id ) { $el_settings = $this->get_block_settings( $page_id, $widget_id ); if ( empty( $el_settings ) ) { $this->redirect_previous_page(); return; } if ( empty( $el_settings['better_payment_paypal_business_email'] ) ) { $this->redirect_previous_page(); return; } if ( 'yes' === $el_settings['better_payment_paypal_live_mode'] ) { $path = 'paypal'; } else { $path = 'sandbox.paypal'; } $el_settings_currency = $el_settings['better_payment_form_currency']; $woo_product_id = ! empty( $el_settings['better_payment_form_woocommerce_product_id'] ) ? intval( $el_settings['better_payment_form_woocommerce_product_id'] ) : 0; $woo_product_ids = ! empty( $el_settings['better_payment_form_woocommerce_product_ids'] ) ? $el_settings['better_payment_form_woocommerce_product_ids'] : array( 0 ); $fluentcart_product_id = ! empty( $el_settings['better_payment_form_fluentcart_product_id'] ) ? intval( $el_settings['better_payment_form_fluentcart_product_id'] ) : 0; $fluentcart_product_ids = ! empty( $el_settings['better_payment_form_fluentcart_product_ids'] ) ? $el_settings['better_payment_form_fluentcart_product_ids'] : array( 0 ); $is_layout_6 = ! empty( $el_settings['better_payment_form_layout'] ) && 'layout-6-pro' === $el_settings['better_payment_form_layout']; $is_fluentcart_layout = $is_layout_6 && ! empty( $el_settings['better_payment_form_layout_6_ecommerce_platform'] ) && 'fluentcart' === $el_settings['better_payment_form_layout_6_ecommerce_platform']; $is_woo_layout = $is_layout_6 && ( empty( $el_settings['better_payment_form_layout_6_ecommerce_platform'] ) || 'woocommerce' === $el_settings['better_payment_form_layout_6_ecommerce_platform'] ); // phpcs:disable WordPress.Security.NonceVerification.Missing // Amount, quantity, currency and campaign come from the stored settings, never // from the request — see PaymentRequestGuard. $guarded = ( new PaymentRequestGuard() )->resolve_form_payment( $el_settings, wp_unslash( $_POST ), array( 'page_id' => $page_id, 'gateway' => 'paypal', ) ); if ( is_wp_error( $guarded ) ) { PaymentRequestGuard::reject_form_post( $guarded ); return; } $el_settings_currency = $guarded['currency']; $el_settings_currency_symbol = $this->get_currency_symbol( esc_html( $el_settings_currency ) ); $primary_payment_amount = $guarded['amount']; $primary_payment_amount_quantity = $guarded['quantity']; $order_id = Handler::new_order_id( 'paypal' ); $paypal_button_type = ! empty( $el_settings['better_payment_paypal_button_type'] ) ? $el_settings['better_payment_paypal_button_type'] : '_xclick'; $site_url = get_permalink( $page_id ); $return_url = ! empty( $_POST['return'] ) ? wp_validate_redirect( esc_url_raw( $_POST['return'] ), $site_url ) : ''; $cancel_return_url = ! empty( $_POST['cancel_return'] ) ? wp_validate_redirect( esc_url_raw( $_POST['cancel_return'] ), $site_url ) : ''; $cancel_return_url = add_query_arg( 'better_payment_paypal_id', $order_id, $cancel_return_url ); $request_data = array( 'business' => $el_settings['better_payment_paypal_business_email'], 'currency_code' => $el_settings_currency, 'rm' => '2', 'return' => $return_url, 'cancel_return' => $cancel_return_url, 'item_number' => $order_id, 'item_name' => ! empty( $el_settings['better_payment_form_title'] ) ? esc_html__( $el_settings['better_payment_form_title'], 'better-payment' ) : esc_html__( 'Better Payment', 'better-payment' ), 'amount' => $primary_payment_amount, 'cmd' => $paypal_button_type, 'notify_url' => admin_url( 'admin-post.php?action=better_payment_paypal_ipn' ), ); $product_ids = array( 'woo_product_ids' => $woo_product_ids, 'fluentcart_product_ids' => $fluentcart_product_ids, ); $detailed_product_info = $this->get_detailed_product_info( $product_ids ); // Form fields data to send via email. $better_form_fields = array( 'amount' => sanitize_text_field( $el_settings_currency_symbol ) . $primary_payment_amount, 'referer_page_id' => $page_id, 'referer_widget_id' => $widget_id, 'woo_product_id' => $woo_product_id, 'woo_product_ids' => maybe_serialize( $woo_product_ids ), 'fluentcart_product_id' => $fluentcart_product_id, 'fluentcart_product_ids' => maybe_serialize( $fluentcart_product_ids ), 'source' => 'paypal', 'amount_quantity' => ! empty( $primary_payment_amount_quantity ) ? intval( $primary_payment_amount_quantity ) : '', 'is_woo_layout' => $is_woo_layout, 'is_fluentcart_layout' => $is_fluentcart_layout, 'detailed_product_info' => maybe_serialize( $detailed_product_info ), 'paypal_business_email' => sanitize_email( $el_settings['better_payment_paypal_business_email'] ), // Persisted so the async PayPal IPN can rebuild the e-mail body + on/off toggle. 'email_settings' => Handler::extract_email_settings( $el_settings ), ); $better_form_fields = array_merge( $better_form_fields, $this->fetch_better_form_fields( $el_settings, $_POST ) ); if ( ! empty( $better_form_fields['primary_first_name'] ) ) { $request_data['primary_first_name'] = sanitize_text_field( $better_form_fields['primary_first_name'] ); } if ( ! empty( $better_form_fields['primary_last_name'] ) ) { $request_data['primary_last_name'] = sanitize_text_field( $better_form_fields['primary_last_name'] ); } if ( ! empty( $better_form_fields['primary_email'] ) ) { $request_data['primary_email'] = sanitize_email( $better_form_fields['primary_email'] ); } if ( ! empty( $better_form_fields['primary_reference_number'] ) ) { $request_data['invoice'] = sanitize_text_field( $better_form_fields['primary_reference_number'] ); } $campaign_id = $guarded['campaign_id']; // phpcs:enable WordPress.Security.NonceVerification.Missing Handler::payment_create( array( 'amount' => floatval( $primary_payment_amount ), 'order_id' => $order_id, 'payment_date' => gmdate( 'Y-m-d H:i:s' ), 'source' => 'paypal', 'form_fields_info' => maybe_serialize( $better_form_fields ), 'currency' => sanitize_text_field( $el_settings_currency ), 'referer' => 'gutenberg-block', 'campaign_id' => $campaign_id, ) ); $paypal_url = "https://www.$path.com/cgi-bin/webscr?"; $paypal_url .= http_build_query( $request_data ); wp_redirect( esc_url_raw( $paypal_url ) ); exit; } /** * Handle Stripe token request for Gutenberg blocks. * * @since 1.0.0 */ public function block_stripe_get_token() { // phpcs:disable WordPress.Security.NonceVerification.Missing // Bail immediately if not a Gutenberg block submission — zero DB overhead for Elementor forms. if ( empty( $_POST['setting_data']['source'] ) || 'gutenberg' !== $_POST['setting_data']['source'] ) { return; } // phpcs:enable WordPress.Security.NonceVerification.Missing // Verify nonce. if ( ! check_admin_referer( 'better-payment', 'security' ) ) { wp_send_json_error( esc_html__( 'Nonce verification failed.', 'better-payment' ) ); return; } // phpcs:disable WordPress.Security.NonceVerification.Missing $page_id = isset( $_POST['setting_data']['page_id'] ) ? intval( $_POST['setting_data']['page_id'] ) : 0; $widget_id = isset( $_POST['setting_data']['widget_id'] ) ? sanitize_text_field( $_POST['setting_data']['widget_id'] ) : ''; // phpcs:enable WordPress.Security.NonceVerification.Missing if ( empty( $page_id ) || empty( $widget_id ) ) { return; // Let the original handler deal with missing data. } // Check if this is a block form by looking for settings. if ( ! $this->is_block_form( $page_id, $widget_id ) ) { return; // Not a block form, let Elementor handler process it. } // This is a block form - handle the Stripe payment here. $this->process_stripe_payment( $page_id, $widget_id ); } /** * Handle Paystack token request for Gutenberg blocks. * * @since 1.0.0 */ public function block_paystack_get_token() { // phpcs:disable WordPress.Security.NonceVerification.Missing // Bail immediately if not a Gutenberg block submission — zero DB overhead for Elementor forms. if ( empty( $_POST['setting_data']['source'] ) || 'gutenberg' !== $_POST['setting_data']['source'] ) { return; } // phpcs:enable WordPress.Security.NonceVerification.Missing // Verify nonce. if ( ! check_admin_referer( 'better-payment', 'security' ) ) { return; } // phpcs:disable WordPress.Security.NonceVerification.Missing $page_id = isset( $_POST['setting_data']['page_id'] ) ? intval( $_POST['setting_data']['page_id'] ) : 0; $widget_id = isset( $_POST['setting_data']['widget_id'] ) ? sanitize_text_field( $_POST['setting_data']['widget_id'] ) : ''; // phpcs:enable WordPress.Security.NonceVerification.Missing if ( empty( $page_id ) || empty( $widget_id ) ) { return; // Let the original handler deal with missing data. } // Check if this is a block form by looking for transient settings. if ( ! $this->is_block_form( $page_id, $widget_id ) ) { return; // Not a block form, let Elementor handler process it. } // This is a block form - handle the Paystack payment here. $this->process_paystack_payment( $page_id, $widget_id ); } /** * Process Stripe payment for block forms. * * @param int $page_id The page ID. * @param string $widget_id The widget/block ID. */ private function process_stripe_payment( $page_id, $widget_id ) { $el_settings = $this->get_block_settings( $page_id, $widget_id ); if ( empty( $el_settings ) ) { wp_send_json_error( esc_html__( 'Setting Data is missing', 'better-payment' ) ); } $better_payment_keys = array( 'public_key' => 'yes' === sanitize_text_field( $el_settings['better_payment_stripe_live_mode'] ) ? sanitize_text_field( $el_settings['better_payment_stripe_public_key_live'] ) : sanitize_text_field( $el_settings['better_payment_stripe_public_key'] ), 'secret_key' => 'yes' === sanitize_text_field( $el_settings['better_payment_stripe_live_mode'] ) ? sanitize_text_field( $el_settings['better_payment_stripe_secret_key_live'] ) : sanitize_text_field( $el_settings['better_payment_stripe_secret_key'] ), ); if ( empty( $better_payment_keys['public_key'] ) || empty( $better_payment_keys['secret_key'] ) ) { wp_send_json_error( esc_html__( 'Stripe Key missing', 'better-payment' ) ); } // phpcs:disable WordPress.Security.NonceVerification.Missing // Amount, quantity, currency and campaign come from the stored settings, never // from the request — see PaymentRequestGuard. $guarded = ( new PaymentRequestGuard() )->resolve_form_payment( $el_settings, isset( $_POST['fields'] ) && is_array( $_POST['fields'] ) ? wp_unslash( $_POST['fields'] ) : array(), array( 'page_id' => $page_id, 'gateway' => 'stripe', ) ); if ( is_wp_error( $guarded ) ) { wp_send_json_error( esc_html( $guarded->get_error_message() ) ); return; } $amount = $guarded['amount']; $amount_quantity = $guarded['quantity']; $header_info = array( 'Authorization' => 'Basic ' . base64_encode( sanitize_text_field( $better_payment_keys['secret_key'] ) . ':' ), 'Stripe-Version' => '2019-05-16', ); $order_id = Handler::new_order_id( 'stripe' ); $el_settings_currency = $guarded['currency']; $el_settings_currency_symbol = $this->get_currency_symbol( esc_html( $el_settings_currency ) ); $redirection_url_success = get_permalink( $page_id ); $redirection_url_error = get_permalink( $page_id ); $redirection_url_success = add_query_arg( array( 'better_payment_stripe_status' => 'success', 'better_payment_widget_id' => $widget_id, ), $redirection_url_success ); $redirection_url_error = add_query_arg( array( 'better_payment_error_status' => 'error', 'better_payment_widget_id' => $widget_id, ), $redirection_url_error ); // Build form fields. $woo_product_id = ! empty( $el_settings['better_payment_form_woocommerce_product_id'] ) ? intval( $el_settings['better_payment_form_woocommerce_product_id'] ) : 0; $woo_product_ids = ! empty( $el_settings['better_payment_form_woocommerce_product_ids'] ) ? $el_settings['better_payment_form_woocommerce_product_ids'] : array( 0 ); $fluentcart_product_id = ! empty( $el_settings['better_payment_form_fluentcart_product_id'] ) ? intval( $el_settings['better_payment_form_fluentcart_product_id'] ) : 0; $fluentcart_product_ids = ! empty( $el_settings['better_payment_form_fluentcart_product_ids'] ) ? $el_settings['better_payment_form_fluentcart_product_ids'] : array( 0 ); $product_ids = array( 'woo_product_ids' => $woo_product_ids, 'fluentcart_product_ids' => $fluentcart_product_ids, ); $detailed_product_info = $this->get_detailed_product_info( $product_ids ); $better_form_fields = array( 'amount' => sanitize_text_field( $el_settings_currency_symbol ) . $amount, 'referer_page_id' => $page_id, 'referer_widget_id' => $widget_id, 'woo_product_id' => $woo_product_id, 'woo_product_ids' => maybe_serialize( $woo_product_ids ), 'fluentcart_product_id' => $fluentcart_product_id, 'fluentcart_product_ids' => maybe_serialize( $fluentcart_product_ids ), 'source' => 'stripe', 'amount_quantity' => ! empty( $amount_quantity ) ? intval( $amount_quantity ) : '', 'detailed_product_info' => maybe_serialize( $detailed_product_info ), ); $better_form_fields = array_merge( $better_form_fields, $this->fetch_better_form_fields( $el_settings, $_POST['fields'] ) ); $item_name = ! empty( $el_settings['better_payment_form_title'] ) ? esc_html__( $el_settings['better_payment_form_title'], 'better-payment' ) : esc_html__( 'Better Payment', 'better-payment' ); // The Stripe Price ID (when Payment Source = Stripe) is display-only — // it pre-fills the amount input on the frontend (see layout-1/2/3.php line input value). // The payment session always uses price_data with the submitted amount, // matching the Elementor widget behaviour for layouts 1/2/3. $line_item = array( 'price_data' => array( 'currency' => sanitize_text_field( $el_settings_currency ), 'unit_amount' => intval( $amount * 100 ), 'product_data' => array( 'name' => $item_name, ), ), 'quantity' => 1, ); $request_body = array( 'line_items' => array( $line_item ), 'mode' => 'payment', 'locale' => 'auto', 'payment_method_types' => array( 'card' ), 'billing_address_collection' => 'required', 'client_reference_id' => time(), 'metadata' => array( 'order_id' => $order_id, ), 'success_url' => esc_url_raw( $redirection_url_success ) . '&better_payment_stripe_id=' . $order_id, 'cancel_url' => add_query_arg( array( 'better_payment_stripe_id' => $order_id, ), esc_url_raw( $redirection_url_error ) ), ); $request_body['payment_intent_data'] = array( 'capture_method' => 'automatic', 'description' => $item_name, 'metadata' => array( 'order_id' => $order_id, ), ); $primary_email = ! empty( $better_form_fields['primary_email'] ) ? sanitize_email( $better_form_fields['primary_email'] ) : ''; if ( ! empty( $primary_email ) ) { $request_body['customer_email'] = $primary_email; $request_body['metadata']['customer_email'] = $primary_email; $request_body['payment_intent_data']['metadata']['customer_email'] = $primary_email; } // Build customer name from first/last name fields (mirrors widget behaviour). $customer_name = ''; if ( ! empty( $better_form_fields['primary_first_name'] ) ) { $customer_name = sanitize_text_field( $better_form_fields['primary_first_name'] ); } if ( ! empty( $better_form_fields['primary_last_name'] ) ) { $customer_name = trim( $customer_name . ' ' . sanitize_text_field( $better_form_fields['primary_last_name'] ) ); } if ( ! empty( $customer_name ) ) { $request_body['metadata']['customer_name'] = $customer_name; $request_body['payment_intent_data']['metadata']['customer_name'] = $customer_name; } $request = wp_remote_post( 'https://api.stripe.com/v1/checkout/sessions', array( 'headers' => $header_info, 'body' => $request_body, ) ); if ( is_wp_error( $request ) ) { wp_send_json_error( sanitize_text_field( $request->get_error_message() ) ); return; } $response_ar = json_decode( wp_remote_retrieve_body( $request ) ); if ( null === $response_ar ) { wp_send_json_error( esc_html__( 'Invalid response from Stripe.', 'better-payment' ) ); return; } if ( ! empty( $response_ar->payment_intent ) || ( ! empty( $response_ar->mode ) && 'subscription' === $response_ar->mode ) ) { $campaign_id = $guarded['campaign_id']; Handler::payment_create( array( 'amount' => floatval( $amount ), 'order_id' => $order_id, 'payment_date' => gmdate( 'Y-m-d H:i:s' ), 'source' => 'stripe', 'transaction_id' => sanitize_text_field( $response_ar->payment_intent ), 'customer_info' => maybe_serialize( $response_ar ), 'form_fields_info' => maybe_serialize( $better_form_fields ), 'obj_id' => sanitize_text_field( $response_ar->id ), 'status' => sanitize_text_field( $response_ar->payment_status ), 'currency' => sanitize_text_field( $el_settings_currency ), 'referer' => 'gutenberg-block', 'campaign_id' => $campaign_id, ) ); wp_send_json_success( array( 'stripe_data' => sanitize_text_field( $response_ar->id ), 'stripe_public_key' => sanitize_text_field( $better_payment_keys['public_key'] ), ) ); } else { $error_message = 'Something went wrong!'; if ( isset( $response_ar->error ) ) { $error_message = sanitize_text_field( $response_ar->error->message ); } wp_send_json_error( $error_message ); } // phpcs:enable WordPress.Security.NonceVerification.Missing } /** * Process Paystack payment for block forms. * * @param int $page_id The page ID. * @param string $widget_id The widget/block ID. */ private function process_paystack_payment( $page_id, $widget_id ) { $el_settings = $this->get_block_settings( $page_id, $widget_id ); if ( empty( $el_settings ) ) { wp_send_json_error( esc_html__( 'Setting Data is missing', 'better-payment' ) ); } if ( empty( $el_settings['better_payment_paystack_public_key'] ) || empty( $el_settings['better_payment_paystack_secret_key'] ) ) { wp_send_json_error( esc_html__( 'Paystack Key missing', 'better-payment' ) ); } // phpcs:disable WordPress.Security.NonceVerification.Missing // Amount, quantity, currency and campaign come from the stored settings, never // from the request — see PaymentRequestGuard. $guarded = ( new PaymentRequestGuard() )->resolve_form_payment( $el_settings, isset( $_POST['fields'] ) && is_array( $_POST['fields'] ) ? wp_unslash( $_POST['fields'] ) : array(), array( 'page_id' => $page_id, 'gateway' => 'paystack', ) ); if ( is_wp_error( $guarded ) ) { wp_send_json_error( esc_html( $guarded->get_error_message() ) ); return; } $amount = $guarded['amount']; $amount_quantity = $guarded['quantity']; $header_info = array( 'Authorization' => 'Bearer ' . sanitize_text_field( $el_settings['better_payment_paystack_secret_key'] ), 'Cache-Control: no-cache', ); $order_id = Handler::new_order_id( 'paystack' ); $el_settings_currency = $guarded['currency']; $el_settings_currency_symbol = $this->get_currency_symbol( esc_html( $el_settings_currency ) ); $redirection_url_success = get_permalink( $page_id ); $redirection_url_error = get_permalink( $page_id ); $redirection_url_success = add_query_arg( array( 'better_payment_paystack_status' => 'success', 'better_payment_widget_id' => $widget_id, ), $redirection_url_success ); $redirection_url_error = add_query_arg( array( 'better_payment_error_status' => 'error', 'better_payment_widget_id' => $widget_id, ), $redirection_url_error ); // Build form fields. $woo_product_id = ! empty( $el_settings['better_payment_form_woocommerce_product_id'] ) ? intval( $el_settings['better_payment_form_woocommerce_product_id'] ) : 0; $woo_product_ids = ! empty( $el_settings['better_payment_form_woocommerce_product_ids'] ) ? $el_settings['better_payment_form_woocommerce_product_ids'] : array( 0 ); $fluentcart_product_id = ! empty( $el_settings['better_payment_form_fluentcart_product_id'] ) ? intval( $el_settings['better_payment_form_fluentcart_product_id'] ) : 0; $fluentcart_product_ids = ! empty( $el_settings['better_payment_form_fluentcart_product_ids'] ) ? $el_settings['better_payment_form_fluentcart_product_ids'] : array( 0 ); $product_ids = array( 'woo_product_ids' => $woo_product_ids, 'fluentcart_product_ids' => $fluentcart_product_ids, ); $detailed_product_info = $this->get_detailed_product_info( $product_ids ); $better_form_fields = array( 'amount' => sanitize_text_field( $el_settings_currency_symbol ) . $amount, 'referer_page_id' => $page_id, 'referer_widget_id' => $widget_id, 'woo_product_id' => $woo_product_id, 'woo_product_ids' => maybe_serialize( $woo_product_ids ), 'fluentcart_product_id' => $fluentcart_product_id, 'fluentcart_product_ids' => maybe_serialize( $fluentcart_product_ids ), 'source' => 'paystack', 'amount_quantity' => ! empty( $amount_quantity ) ? intval( $amount_quantity ) : '', 'detailed_product_info' => maybe_serialize( $detailed_product_info ), ); $better_form_fields = array_merge( $better_form_fields, $this->fetch_better_form_fields( $el_settings, $_POST['fields'] ) ); $primary_email = ! empty( $better_form_fields['primary_email'] ) ? sanitize_email( $better_form_fields['primary_email'] ) : ''; $request_body = array( 'amount' => intval( $amount * 100 ), 'currency' => sanitize_text_field( $el_settings_currency ), 'email' => $primary_email, 'callback_url' => esc_url_raw( $redirection_url_success ) . '&better_payment_paystack_id=' . $order_id, 'metadata' => array( 'cancel_action' => add_query_arg( array( 'better_payment_paystack_id' => $order_id, ), esc_url_raw( $redirection_url_error ) ), ), ); $request = wp_remote_post( 'https://api.paystack.co/transaction/initialize', array( 'headers' => $header_info, 'body' => $request_body, ) ); if ( is_wp_error( $request ) ) { wp_send_json_error( sanitize_text_field( $request->get_error_message() ) ); return; } $response_ar = json_decode( wp_remote_retrieve_body( $request ) ); if ( null === $response_ar ) { wp_send_json_error( esc_html__( 'Invalid response from Paystack.', 'better-payment' ) ); return; } if ( empty( $response_ar->status ) || empty( $response_ar->data ) ) { $error_message = ! empty( $response_ar->message ) ? sanitize_text_field( $response_ar->message ) : 'Something went wrong!'; if ( isset( $response_ar->error ) ) { $error_message = sanitize_text_field( $response_ar->error->message ); } wp_send_json_error( $error_message ); } $campaign_id = $guarded['campaign_id']; Handler::payment_create( array( 'amount' => floatval( $amount ), 'order_id' => $order_id, 'payment_date' => gmdate( 'Y-m-d H:i:s' ), 'source' => 'paystack', // Paystack's reference, so verification can bind it to this order. 'transaction_id' => ! empty( $response_ar->data->reference ) ? sanitize_text_field( $response_ar->data->reference ) : '', 'customer_info' => maybe_serialize( $response_ar ), 'form_fields_info' => maybe_serialize( $better_form_fields ), 'status' => 'unpaid', 'currency' => sanitize_text_field( $el_settings_currency ), 'referer' => 'gutenberg-block', 'campaign_id' => $campaign_id, ) ); $authorization_url = ! empty( $response_ar->data->authorization_url ) ? esc_url_raw( $response_ar->data->authorization_url ) : ''; wp_send_json_success( array( 'authorization_url' => $authorization_url, ) ); // phpcs:enable WordPress.Security.NonceVerification.Missing } /** * Redirect to referer page. * * @since 1.0.0 */ public function redirect_previous_page() { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $location = isset( $_SERVER['HTTP_REFERER'] ) ? wp_unslash( $_SERVER['HTTP_REFERER'] ) : home_url(); wp_safe_redirect( esc_url_raw( $location ) ); exit(); } /** * Get detailed product information. * * @param array $product_ids Array of product IDs. * @param array $product_quantities Array of product quantities. * @return array Detailed product information. */ public function get_detailed_product_info( $product_ids, $product_quantities = array() ) { $detailed_product_info = array(); if ( function_exists( 'wc_get_product' ) && ! empty( $product_ids['woo_product_ids'] ) ) { foreach ( $product_ids['woo_product_ids'] as $key => $product_id ) { if ( empty( $product_id ) ) { continue; } $product = wc_get_product( $product_id ); if ( $product ) { $quantity = isset( $product_quantities[ $key ] ) ? intval( $product_quantities[ $key ] ) : 1; $price = floatval( $product->get_price() ); $total_price = $price * $quantity; $detailed_product_info['woo_products'][ $product_id ] = array( 'name' => sanitize_text_field( $product->get_name() ), 'product_id' => intval( $product_id ), 'permalink' => esc_url( $product->get_permalink() ), 'image_src' => esc_url( wp_get_attachment_url( (int) $product->get_image_id() ) ), 'price' => $price, 'quantity' => $quantity, 'total_price' => $total_price, ); } } } return $detailed_product_info; } /** * Fetch form fields from POST data. * * @param array $el_settings Widget/block settings. * @param array $post_data_form_fields POST data. * @return array Form fields data. */ public function fetch_better_form_fields( $el_settings, $post_data_form_fields ) { $better_form_fields = array(); $post_data_primary_first_name = ''; $post_data_primary_last_name = ''; $post_data_primary_email = ''; $post_fields = $post_data_form_fields; $layout = ! empty( $el_settings['better_payment_form_layout'] ) ? sanitize_text_field( $el_settings['better_payment_form_layout'] ) : 'layout-1'; // Handle different layouts. switch ( $layout ) { case 'layout-4-pro': $el_settings['better_payment_form_fields'] = isset( $el_settings['better_payment_form_fields_layout_4_5_6'] ) ? $el_settings['better_payment_form_fields_layout_4_5_6'] : array(); break; case 'layout-5-pro': $el_settings['better_payment_form_fields'] = isset( $el_settings['better_payment_form_fields_layout_4_5_6_desc'] ) ? $el_settings['better_payment_form_fields_layout_4_5_6_desc'] : array(); break; case 'layout-6-pro': $el_settings['better_payment_form_fields'] = isset( $el_settings['better_payment_form_fields_layout_4_5_6_woo'] ) ? $el_settings['better_payment_form_fields_layout_4_5_6_woo'] : array(); break; default: break; } $form_fields = isset( $el_settings['better_payment_form_fields'] ) ? $el_settings['better_payment_form_fields'] : array(); if ( ! empty( $form_fields ) && is_array( $form_fields ) ) { foreach ( $form_fields as $form_field ) { $field_type = ! empty( $form_field['better_payment_primary_field_type'] ) ? sanitize_text_field( $form_field['better_payment_primary_field_type'] ) : ''; $field_name = ! empty( $form_field['better_payment_field_name_heading'] ) ? sanitize_text_field( $form_field['better_payment_field_name_heading'] ) : ''; switch ( $field_type ) { case 'primary_first_name': $post_data_primary_first_name = isset( $post_fields['primary_first_name'] ) ? sanitize_text_field( $post_fields['primary_first_name'] ) : ''; $better_form_fields['primary_first_name'] = $post_data_primary_first_name; break; case 'primary_last_name': $post_data_primary_last_name = isset( $post_fields['primary_last_name'] ) ? sanitize_text_field( $post_fields['primary_last_name'] ) : ''; $better_form_fields['primary_last_name'] = $post_data_primary_last_name; break; case 'primary_email': $post_data_primary_email = isset( $post_fields['primary_email'] ) ? sanitize_email( $post_fields['primary_email'] ) : ''; $better_form_fields['primary_email'] = $post_data_primary_email; break; default: if ( isset( $post_fields[ $field_type ] ) ) { $better_form_fields[ $field_type ] = sanitize_text_field( $post_fields[ $field_type ] ); } break; } } } return $better_form_fields; } }